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 }
View Code

 

posted on 2016-03-02 17:24  ACMICPC  阅读(294)  评论(0编辑  收藏  举报

导航