bzoj 2589 Count on a tree II

Description

给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v),你需要回答u xor lastans和v这两个节点间有多少种不同的点权。其中lastans是上一个询问的答案,初始为0,即第一个询问的u是明文。
 

 

Input

第一行两个整数N,M。
第二行有N个整数,其中第i个整数表示点i的权值。
后面N-1行每行两个整数(x,y),表示点x到点y有一条边。
最后M行每行两个整数(u,v),表示一组询问。
 

 

数据范围是N<=40000 M<=100000 点权在int范围内 

Output

 
M行,表示每个询问的答案。
 

Sample Input

8 2
105 2 9 3 8 5 7 7
1 2
1 3
1 4
3 5
3 6
3 7
4 8
2 5
3 8

Sample Output

4
4
 
 
 
思路: 
 
这题的原先版本是spoj上的题目,那个题目没有强制要求在线,可以使用树上莫队ac。  
 
本题强制要求在线,所以我们要在树上采用分块方法,然后采用类似莫队的思想。  
 
 
 
 
首先,把树分成n^(1/3) 块。 
 
每个块定一个点作为中心,预处理两两中心之间的答案。然后每次询问找到那两个点的中心,像莫队那样暴力移动。显然每次最多移动n^(2/3)次。
 
所以复杂度m*n^(2/3)。
这样的时间复杂度理论上可以通过的,但是bzoj的服务器实在太弱了,于是被卡常了。。。
 
  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 int const N = 40000 + 3;
  4 int const M = 100000 + 3;
  5 int const C = 40;
  6 struct edge {
  7     int to, nt;
  8 } e[N << 1];
  9 int tin[N], tout[N], h[N], cnt, sum, dep[N], f[N][16], a[N], b[N], n, m, st[N], top, sz, bl[N], num, cap[42];
 10 int c[42][42][N], kind[42][42], last;
 11 bool vis[42][42][N];
 12 template<class T>void read(T &x) {
 13     x = 0;
 14     char c = 0;
 15     while(!isdigit(c)) c = getchar();
 16     while(isdigit(c)) x = x * 10 + (c ^ 48), c = getchar();
 17 }
 18 void dfs(int x, int fa) {
 19     tin[x] = ++sum;
 20     f[x][0] = fa;
 21     dep[x] = dep[fa] + 1;
 22     for(int i = h[x]; i; i = e[i].nt) {
 23         int v = e[i].to;
 24         if(v == fa) continue;
 25         dfs(v, x);
 26     }
 27     tout[x] = ++sum;
 28 }
 29 
 30 void add(int a, int b) {
 31     e[++cnt].to = b;
 32     e[cnt].nt = h[a];
 33     h[a] = cnt;
 34 }
 35 void dfs2(int x, int fa) {
 36     int now = top;
 37     for(int i = h[x]; i; i = e[i].nt) {
 38         int v = e[i].to;
 39         if(v == fa) continue;
 40         dfs2(v, x);
 41         int tmp = top - now;
 42         if(tmp >= sz) {
 43             num++;
 44             while(tmp--) {
 45                 int t = st[top--];
 46                 cap[num] = x;
 47                 bl[t] = num;
 48             }
 49         }
 50     }
 51     st[++top] = x;
 52 }
 53 int ancestor(int x, int y) {
 54     return tin[x] <= tin[y] && tout[y] <= tout[x];
 55 }
 56 int lca(int x, int y) {
 57     if(ancestor(x, y)) return x;
 58     if(ancestor(y, x)) return y;
 59     for(int i = 15; i >= 0; i--)
 60         if(!ancestor(f[x][i], y))
 61             x = f[x][i];
 62     return f[x][0];
 63 }
 64 int update(int i, int j, int x) {
 65     if(vis[i][j][x]) {
 66         if(--c[i][j][a[x]] == 0) --kind[i][j];
 67     } else {
 68         if(++c[i][j][a[x]] == 1) ++kind[i][j];
 69     }
 70     vis[i][j][x] ^= 1;
 71 }
 72 int calc(int i, int j, int x, int y) {
 73     if(dep[x] < dep[y])
 74         swap(x, y);
 75     while(dep[x] > dep[y]) {
 76         update(i, j, x);
 77         x = f[x][0];
 78     }
 79     while(x ^ y) {
 80         update(i, j, x);
 81         update(i, j, y);
 82         x = f[x][0];
 83         y = f[y][0];
 84     }
 85 }
 86 int main() {
 87     scanf("%d%d", &n, &m);
 88     sz = max(1, n / C);
 89     for(int i = 1; i <= n; i++)
 90         read(a[i]), b[i] = a[i];
 91     sort(b + 1, b + n + 1);
 92     int k = unique(b + 1, b + n + 1) - b - 1;
 93     for(int i = 1; i <= n; i++)
 94         a[i] = lower_bound(b + 1, b + k + 1, a[i]) - b;
 95     for(int i = 1; i < n; i++) {
 96         int x, y;
 97         read(x);
 98         read(y);
 99         add(x, y);
100         add(y, x);
101     }
102     dfs(1, 1);
103     for(int j = 1; j <= 15; j++)
104         for(int i = 1; i <= n; i++)
105             f[i][j] = f[f[i][j - 1]][j - 1];
106     dfs2(1, 1);
107     if(top) {
108         ++num;
109         cap[num] = 1;
110         while(top) bl[st[top--]] = num;
111     }
112     for(int i = 1; i <= num; i++)
113         for(int j = i + 1; j <= num; j++) {
114             calc(i, j, cap[i], cap[j]);
115         }
116     while(m--) {
117         int x, y;
118         read(x);
119         read(y);
120         x ^= last;
121         int c = min(bl[x], bl[y]);
122         int d = max(bl[x], bl[y]);
123         calc(c, d, cap[bl[x]], x);
124         calc(c, d, cap[bl[y]], y);
125         update(c, d, lca(x, y));
126         printf("%d\n", last = kind[c][d]);
127         calc(c, d, cap[bl[x]], x);
128         calc(c, d, cap[bl[y]], y);
129         update(c, d, lca(x, y));
130     }
131     return 0;
132 }
View Code

 

方法2: 按照深度分块

先分成大小为根号n的块,然后用可持久化块状数组存下每个点到根的路径上所有权值出现的最大深度,预处理好每个块顶到所有点的答案。

然后每个询问,块内的暴力查,如果在不同块,选择块顶的深度较大的点,找到它到另一个点的答案。

这样以后只要处理这个点到块顶的那条链就行了,由于我们已经预处理了每种权值的最大深度,所以我们可以判断每种权值是否已经出现了。

时间复杂度$O(n^{\frac{3}{2}})$ 

理论上貌似比前一种方法好很多,但实际常数巨大,在我们本机上n=40000,m=100000,发现方法1跑了700ms,方法2跑了300多ms。 

 

 

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 int const N = 40000 + 3;
  4 int const K = 200 + 3;
  5 int const D = 16;
  6 int n, m, ans[K][N], a[N], l[N], head[N], cnt, sz, p[N][K], kind, P[N], B[N], T[N][K];
  7 int fa[N][D], dep[N], bel[N], rt[K], f[N], last, q[N], top, num, sum;
  8 template<class T>void read(T &x) {
  9     x = 0;
 10     char c = 0;
 11     while(!isdigit(c)) c = getchar();
 12     while(isdigit(c))  x = x * 10 + (c ^ 48), c = getchar();
 13 }
 14 struct edge {
 15     int to, nt;
 16 } e[N << 1];
 17 void add(int a, int b) {
 18     e[++cnt].to = b;
 19     e[cnt].nt = head[a];
 20     head[a] = cnt;
 21 }
 22 int update(int x, int f) {
 23     memcpy(T[x], T[f], sizeof(T[0]));
 24     T[x][B[a[x]]] = ++sum;
 25     memcpy(p[sum], p[T[f][B[a[x]]]], sizeof(p[0]));
 26     p[sum][P[a[x]]] = dep[x];
 27 }
 28 int  dfs(int x, int f) {
 29     fa[x][0] = f;
 30     update(x, f);
 31     q[++top] = x;
 32     int mxdp = dep[x], beg = top;
 33     for(int i = head[x]; i; i = e[i].nt) {
 34         int v = e[i].to;
 35         if(v == f) continue;
 36         dep[v] = dep[x] + 1;
 37         mxdp = max(mxdp, dfs(v, x));
 38     }
 39     if(mxdp - dep[x] >= sz || beg == 1) {
 40         rt[++num] = x;
 41         for(int i = beg; i <= top; i++) bel[q[i]] = num;
 42         top = beg - 1;
 43         return dep[x] - 1;
 44     }
 45     return mxdp;
 46 }
 47 void getans(int x, int fat, int from) {
 48     if(++f[a[x]] == 1) ++kind;
 49     ans[from][x] = kind;
 50     for(int i = head[x]; i; i = e[i].nt) {
 51         if(e[i].to == fat) continue;
 52         getans(e[i].to, x, from);
 53     }
 54     if(!--f[a[x]]) --kind;
 55 }
 56 int lca(int x, int y) {
 57     if(dep[x] < dep[y]) swap(x, y);
 58     for(int i = 15; i >= 0; i--)
 59         if(dep[fa[x][i]] >= dep[y])
 60             x = fa[x][i];
 61     if(x == y) return x;
 62     for(int i = 15; i >= 0; i--)
 63         if(fa[x][i] != fa[y][i])
 64             x = fa[x][i], y = fa[y][i];
 65     return fa[x][0];
 66 }
 67 int solve_force(int x, int y) {
 68     for(top = kind = 0; x != y; x = fa[x][0]) {
 69         if(dep[x] < dep[y]) swap(x, y);
 70         if(!f[a[x]]++) {
 71             ++kind;
 72             q[++top] = a[x];
 73         }
 74     }
 75     int ans = kind + (!f[a[x]]);
 76     for(; top; --top) f[q[top]] = 0;
 77     return ans;
 78 }
 79 inline int g(int x, int y) {
 80     return p[T[x][B[y]]][P[y]];
 81 }
 82 int solve_block(int x, int y) {
 83     if(dep[rt[bel[x]]] < dep[rt[bel[y]]]) swap(x, y);
 84     int sum = ans[bel[x]][y];
 85     int z = rt[bel[x]], d = dep[lca(x, y)];
 86     for(; x != z; x = fa[x][0]) {
 87         if(!f[a[x]] && g(z, a[x]) < d && g(y, a[x]) < d) {
 88             f[q[++top] = a[x]] = 1;
 89             ++sum;
 90         }
 91     }
 92     for(; top; --top) f[q[top]] = 0;
 93     return sum;
 94 }
 95 int main() {
 96     scanf("%d%d", &n, &m);
 97     sz = sqrt(n);
 98     for(int i = 1; i <= n; i++)
 99         B[i] = (i - 1) / sz + 1, P[i] = i % sz;
100     for(int i = 1; i <= n; i++)
101         read(a[i]), l[i] = a[i];
102     sort(l + 1, l + n + 1);
103     int tot = unique(l + 1, l + n + 1) - l - 1;
104     for(int i = 1; i <= n; i++) a[i] = lower_bound(l + 1, l + tot + 1, a[i]) - l;
105     for(int i = 1; i < n; i++) {
106         int x, y;
107         read(x);
108         read(y);
109         add(x, y);
110         add(y, x);
111     }
112     dep[1] = 1;
113     dfs(1, 0);
114     fa[1][0] = 1;
115     for(int i = 1; i <= num; i++) getans(rt[i], 0, i);
116     for(int j = 1; j <= 15; j++)
117         for(int i = 1; i <= n; i++)
118             fa[i][j] = fa[fa[i][j - 1]][j - 1];
119     while(m--) {
120         int x, y;
121         read(x);
122         read(y);
123         x ^= last;
124         if(bel[x] == bel[y])  printf("%d\n", last = solve_force(x, y));
125         else printf("%d\n", last = solve_block(x, y));
126     }
127     return 0;
128 }
View Code

 

 

转载于:https://www.cnblogs.com/ZJXXCN/p/10684055.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值