BZOJ2588 Spoj 10628. Count on a tree
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ2588 Spoj 10628. Count on a tree相关的知识,希望对你有一定的参考价值。
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2588
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了?
1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 #include <cstring> 5 #define rep(i,l,r) for(int i=l; i<=r; i++) 6 #define clr(x,y) memset(x,y,sizeof(x)) 7 #define travel(x) for(Edge *p=last[x]; p; p=p->pre) 8 using namespace std; 9 const int maxn = 100010; 10 inline int read(){ 11 int ans = 0, f = 1; 12 char c = getchar(); 13 for(; !isdigit(c); c = getchar()) 14 if (c == ‘-‘) f = -1; 15 for(; isdigit(c); c = getchar()) 16 ans = ans * 10 + c - ‘0‘; 17 return ans * f; 18 } 19 struct Edge{ 20 Edge* pre; int to,cost; 21 }edge[maxn<<1],*last[maxn],*pt = edge; 22 int n,m,k,x,y,N,cnt=0,lastans=0,w[maxn],id[maxn],dep[maxn],fa[maxn],size[maxn],top[maxn]; 23 int rt[maxn],ls[maxn*20],rs[maxn*20],sum[maxn*20]; 24 bool vis[maxn]; 25 inline void addedge(int x,int y){ 26 pt->pre = last[x]; pt->to = y; last[x] = pt++; 27 } 28 void dfs(int x){ 29 vis[x] = 1; size[x] = 1; 30 travel(x){ 31 if (vis[p->to]) continue; 32 dep[p->to] = dep[x] + 1; 33 fa[p->to] = x; 34 dfs(p->to); size[x] += size[p->to]; 35 } 36 } 37 void dfs(int x,int chain){ 38 int k = 0; top[x] = chain; 39 travel(x) if (dep[p->to] > dep[x] && size[p->to] > size[k]) k = p->to; 40 if (!k) return; 41 dfs(k,chain); 42 travel(x) if (p->to != k && dep[p->to] > dep[x]) 43 dfs(p->to,p->to); 44 } 45 inline int lca(int x,int y){ 46 while (top[x] != top[y]){ 47 if (dep[top[x]] < dep[top[y]]) swap(x,y); 48 x = fa[top[x]]; 49 } 50 return dep[x] < dep[y] ? x : y; 51 } 52 void insert(int l,int r,int x,int &y,int v){ 53 y = ++cnt; sum[y] = sum[x] + 1; 54 if (l == r) return; 55 ls[y] = ls[x]; rs[y] = rs[x]; 56 int mid = (l + r) >> 1; 57 if (v <= mid) insert(l,mid,ls[x],ls[y],v); 58 else insert(mid+1,r,rs[x],rs[y],v); 59 } 60 int query(int x,int y,int k){ 61 int a = x, b = y, c = lca(x,y), d = fa[c]; 62 a = rt[a], b = rt[b], c = rt[c], d = rt[d]; 63 int l = 1, r = N; 64 while (l < r){ 65 int mid = (l + r) >> 1; 66 int now = sum[ls[a]] + sum[ls[b]] - sum[ls[c]] - sum[ls[d]]; 67 if (now >= k) r = mid, a = ls[a], b = ls[b], c = ls[c], d = ls[d]; 68 else k -= now, l = mid + 1, a = rs[a], b = rs[b], c = rs[c], d = rs[d]; 69 } 70 return id[l]; 71 } 72 void build(int x){ 73 travel(x) if (p->to != fa[x]) insert(1,N,rt[x],rt[p->to],w[p->to]); 74 travel(x) if (p->to != fa[x]) build(p->to); 75 } 76 int main(){ 77 n = read(); m = read(); clr(last,0); 78 rep(i,1,n) w[i] = id[i] = read(); 79 rep(i,1,n-1){ 80 x = read(); y = read(); addedge(x,y); addedge(y,x); 81 } 82 sort(id+1,id+n+1); 83 N = unique(id+1,id+n+1) - id - 1; 84 rep(i,1,n) w[i] = lower_bound(id+1,id+N+1,w[i]) - id; 85 clr(vis,0); dep[1] = 0; fa[1] = 0; dfs(1); dfs(1,1); 86 insert(1,N,rt[0],rt[1],w[1]); 87 build(1); 88 rep(i,1,m){ 89 x = read(); y = read(); k = read(); 90 x ^= lastans; 91 lastans = query(x,y,k); 92 printf("%d",lastans); 93 if (i != m) printf("\n"); 94 } 95 return 0; 96 }
以上是关于BZOJ2588 Spoj 10628. Count on a tree的主要内容,如果未能解决你的问题,请参考以下文章
BZOJ 2588: Spoj 10628. Count on a tree [树上主席树]
BZOJ2588 Spoj 10628. Count on a tree
[BZOJ2588][Spoj 10628]Count on a tree
bzoj 2588: Spoj 10628. Count on a tree LCA+主席树