BZOJ2588 Spoj 10628. Count on a tree
2016-03-02 17:24
369 查看
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2588
第二行有N个整数,其中第i个整数表示点i的权值。
后面N-1行每行两个整数(x,y),表示点x到点y有一条边。
最后M行每行两个整数(u,v,k),表示一组询问。
建立一棵可持久化权值线段树,对于树上的每一个点,以它的父亲节点为上一个版本,根节点的父亲节点是0
询问u与v节点之间第K小的点权,就是询问 (root,u) + (root,v) - (root,lca(u,v)) - (root,fa(lca(u,v))) 第K小的点权,在权值线段树上二分即可。
debug记:建可持久化线段树要从根节点往下建而不是按照点的编号建。不要把建树写残。
Orz教主的指针版主席树,跑得比香港记者还快……
2016.3.2 17:34 update:这份代码在SPOJ上跑了#16……教主的居然WA了?
View Code
Description
给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权。其中lastans是上一个询问的答案,初始为0,即第一个询问的u是明文。Input
第一行两个整数N,M。第二行有N个整数,其中第i个整数表示点i的权值。
后面N-1行每行两个整数(x,y),表示点x到点y有一条边。
最后M行每行两个整数(u,v,k),表示一组询问。
Output
M行,表示每个询问的答案。建立一棵可持久化权值线段树,对于树上的每一个点,以它的父亲节点为上一个版本,根节点的父亲节点是0
询问u与v节点之间第K小的点权,就是询问 (root,u) + (root,v) - (root,lca(u,v)) - (root,fa(lca(u,v))) 第K小的点权,在权值线段树上二分即可。
debug记:建可持久化线段树要从根节点往下建而不是按照点的编号建。不要把建树写残。
Orz教主的指针版主席树,跑得比香港记者还快……
2016.3.2 17:34 update:这份代码在SPOJ上跑了#16……教主的居然WA了?
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #define rep(i,l,r) for(int i=l; i<=r; i++) #define clr(x,y) memset(x,y,sizeof(x)) #define travel(x) for(Edge *p=last[x]; p; p=p->pre) using namespace std; const int maxn = 100010; inline int read(){ int ans = 0, f = 1; char c = getchar(); for(; !isdigit(c); c = getchar()) if (c == '-') f = -1; for(; isdigit(c); c = getchar()) ans = ans * 10 + c - '0'; return ans * f; } struct Edge{ Edge* pre; int to,cost; }edge[maxn<<1],*last[maxn],*pt = edge; int n,m,k,x,y,N,cnt=0,lastans=0,w[maxn],id[maxn],dep[maxn],fa[maxn],size[maxn],top[maxn]; int rt[maxn],ls[maxn*20],rs[maxn*20],sum[maxn*20]; bool vis[maxn]; inline void addedge(int x,int y){ pt->pre = last[x]; pt->to = y; last[x] = pt++; } void dfs(int x){ vis[x] = 1; size[x] = 1; travel(x){ if (vis[p->to]) continue; dep[p->to] = dep[x] + 1; fa[p->to] = x; dfs(p->to); size[x] += size[p->to]; } } void dfs(int x,int chain){ int k = 0; top[x] = chain; travel(x) if (dep[p->to] > dep[x] && size[p->to] > size[k]) k = p->to; if (!k) return; dfs(k,chain); travel(x) if (p->to != k && dep[p->to] > dep[x]) dfs(p->to,p->to); } inline int lca(int x,int y){ while (top[x] != top[y]){ if (dep[top[x]] < dep[top[y]]) swap(x,y); x = fa[top[x]]; } return dep[x] < dep[y] ? x : y; } void insert(int l,int r,int x,int &y,int v){ y = ++cnt; sum[y] = sum[x] + 1; if (l == r) return; ls[y] = ls[x]; rs[y] = rs[x]; int mid = (l + r) >> 1; if (v <= mid) insert(l,mid,ls[x],ls[y],v); else insert(mid+1,r,rs[x],rs[y],v); } int query(int x,int y,int k){ int a = x, b = y, c = lca(x,y), d = fa[c]; a = rt[a], b = rt[b], c = rt[c], d = rt[d]; int l = 1, r = N; while (l < r){ int mid = (l + r) >> 1; int now = sum[ls[a]] + sum[ls[b]] - sum[ls[c]] - sum[ls[d]]; if (now >= k) r = mid, a = ls[a], b = ls[b], c = ls[c], d = ls[d]; else k -= now, l = mid + 1, a = rs[a], b = rs[b], c = rs[c], d = rs[d]; } return id[l]; } void build(int x){ travel(x) if (p->to != fa[x]) insert(1,N,rt[x],rt[p->to],w[p->to]); travel(x) if (p->to != fa[x]) build(p->to); } int main(){ n = read(); m = read(); clr(last,0); rep(i,1,n) w[i] = id[i] = read(); rep(i,1,n-1){ x = read(); y = read(); addedge(x,y); addedge(y,x); } sort(id+1,id+n+1); N = unique(id+1,id+n+1) - id - 1; rep(i,1,n) w[i] = lower_bound(id+1,id+N+1,w[i]) - id; clr(vis,0); dep[1] = 0; fa[1] = 0; dfs(1); dfs(1,1); insert(1,N,rt[0],rt[1],w[1]); build(1); rep(i,1,m){ x = read(); y = read(); k = read(); x ^= lastans; lastans = query(x,y,k); printf("%d",lastans); if (i != m) printf("\n"); } return 0; }
View Code
相关文章推荐
- BZOJ4013: [HNOI2015]实验比较
- Java关键字——super
- Thymeleaf中each标签遍历list如何获取index
- 终于转到IOS的学习了!!
- 推荐书籍系列(4) -- node.js&docker
- Oracle11g数据库空表不能导出解决办法
- MySQL常用指令
- 【高性能】Matlab的并行计算之spmd
- 10 个值得一试的开源深度学习框架
- 选择HttpHandler还是HttpModule?
- C++中ShallowCopy和DeepCopy的区别
- Platform Dependent Compilation
- 浅析人脸检测之Haar分类器方法
- system Function
- 【千里之行,始于足下】游戏服务端开发--开发语言篇
- import&export
- 详解TCP协议的服务特点以及连接建立与终止的过程(俗称三次握手四次挥手)
- xml文件的xsd验证失败信息
- 数据库SQL优化大总结之 百万级数据库优化方案
- android进程间通信:使用AIDL