bzoj 3351 [ioi2009]Regions
Posted zjxxcn
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj 3351 [ioi2009]Regions相关的知识,希望对你有一定的参考价值。
N个节点的树,有R种属性,每个点属于一种属性。有Q次询问,每次询问r1,r2,回答有多少对(e1,e2)满足e1属性是r1,e2属性是r2,e1是e2的祖先。
数据规模
N≤200000,R≤25000,Q≤200000
N≤200000,R≤25000,Q≤200000
30%数据R≤500
55%数据同种属性节点个数≤500
Input
Output
Sample Input
6 3 4
1
1 2
1 3
2 3
2 3
5 1
1 2
1 3
2 3
3 1
1
1 2
1 3
2 3
2 3
5 1
1 2
1 3
2 3
3 1
Sample Output
1
3
2
1
3
2
1
思路:
这题我采用了一点分块算法,根据我的测试,题目好像没有r1=r2的情况。
对于r2的颜色出现次数小于500的情况,我们可以暴力解决, 时间复杂复$O(500*n)$
对于r2的颜色出现超过500次的情况,由于这样的颜色不会超过400个,所以我们分块统计每个块里面这种颜色有几个。
son[i][j]表示第i块里面第j种颜色有几个。
分块我采用的按照size分块的方法,构建了虚树,可以保证块的大小和联通,但是不能保证块的数量。
块内暴力解决,块间采用一些预处理,由于需要map,我的时间复杂度几乎炸了。
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define mp make_pair 4 #define pii pair<int,int> 5 int const N = 200000 + 3; 6 int const sz = 1000; 7 struct edge { 8 int to, nt; 9 } e[N << 1]; 10 int n, r, q, ans[N], v[N], cnt, h[N], num[N], ct[N], bl[N], c[10000][500], nb, id[N], nc; 11 // 这里我们按照size分块 12 // v 表示每个点的颜色 13 // ans 表示答案 14 // num 表示每个颜色出现的次数,也表示分块以后每个块里面点的数量 15 // ct 表示每种颜色出现的次数 16 // bl 表示每个点分别属于哪个块 17 // c数组表示每个块里面超过sz的颜色的点的数量 18 // nb 表示块的数量 19 // id 表示超过sz的颜色的新编号 20 // nc表示超过sz的颜色的数量 21 // a vector表示小于等于sz的那些询问 22 // b 表示小于等于sz的那些询问的编号 23 // vex 记录哪个块里面有哪些点。 24 // H 记录虚树 25 // cp表示每一块的顶端节点 26 int H[N], tin[N], tout[N], sum, cp[N], son[10000][500],yl[N],tq,pos[N]; 27 vector<int> a[N], b[N], vex[10000]; 28 map<pii, int> mat; 29 void add(int a, int b) { 30 e[++cnt].to = b; 31 e[cnt].nt = h[a]; 32 h[a] = cnt; 33 } 34 int Add(int a, int b) { 35 e[++cnt].to = b; 36 e[cnt].nt = H[a]; 37 H[a] = cnt; 38 } 39 void dfs(int x) { 40 num[v[x]]++; 41 if(ct[v[x]] <= sz) { 42 for(int i = 0; i < a[v[x]].size(); i++) { 43 int t = a[v[x]][i]; 44 ans[b[v[x]][i]] += num[t]; 45 } 46 } 47 for(int i = h[x]; i; i = e[i].nt) 48 dfs(e[i].to); 49 num[v[x]]--; 50 } 51 void dfs2(int x, int fa) { 52 tin[x] = ++sum; 53 if(num[bl[fa]] >= sz) { 54 nb++; 55 cp[nb] = x; 56 Add(bl[fa], nb); 57 } 58 bl[x] = nb; 59 num[nb]++; 60 if(ct[v[x]] > sz) 61 son[nb][id[v[x]]]++; 62 for(int i = h[x]; i; i = e[i].nt) 63 dfs2(e[i].to, x); 64 tout[x] = ++sum; 65 } 66 inline int ancestor(int x, int y) { 67 return tin[x] <= tin[y] && tout[y] <= tout[x]; 68 } 69 void dfs3(int x) { 70 for(int i = H[x]; i; i = e[i].nt) { 71 int s = e[i].to; 72 dfs3(s); 73 for(int j = 1; j <= nc; j++) 74 son[x][j] += son[s][j]; 75 } 76 } 77 void ask(int x) { 78 for(int i = 0; i < vex[x].size(); i++) { 79 for(int j = H[x]; j; j = e[j].nt) { 80 int a = vex[x][i]; 81 int b = cp[e[j].to]; 82 if(!ancestor(a, b)) 83 continue; 84 for(int cl = 1; cl <= nc; cl++) { 85 int t = mat[mp(v[a], pos[cl])]; 86 if(!t) 87 continue; 88 ans[t] += son[e[j].to][cl]; 89 } 90 } 91 } 92 for(int i = H[x]; i; i = e[i].nt) 93 ask(e[i].to); 94 } 95 int main() { 96 scanf("%d%d%d", &n, &r, &q); 97 scanf("%d", &v[1]); 98 ct[v[1]]++; 99 for(int i = 2; i <= n; i++) { 100 int x, y; 101 scanf("%d%d", &x, &y); 102 add(x, i); 103 v[i] = y; 104 ct[v[i]]++; 105 } 106 for(int i = 1; i <= r; i++) 107 if(ct[i] > sz) { 108 id[i] = ++nc; 109 pos[nc]=i; 110 } 111 for(int i = 1; i <= q; i++) { 112 int x, y; 113 scanf("%d%d", &x, &y); 114 if(mat.find(mp(x,y))==mat.end()) { 115 mat[mp(x,y)]=++tq; 116 a[y].push_back(x); 117 b[y].push_back(tq); 118 } 119 yl[i]=mat[mp(x,y)]; 120 } 121 cp[0] = 1; 122 dfs(1); 123 memset(num, 0, sizeof(num)); 124 dfs2(1, 1); 125 for(int i = 1; i <= n; i++) 126 vex[bl[i]].push_back(i); 127 for(int i = 0; i <= nb; i++) { 128 for(int j = 0; j < vex[i].size(); j++) 129 for(int k = 0; k < vex[i].size(); k++) { 130 int x = v[vex[i][j]]; 131 int y = v[vex[i][k]]; 132 if(vex[i][j]==vex[i][k]) 133 continue; 134 if(!ancestor(vex[i][j], vex[i][k])) 135 continue; 136 if(ct[y] <= sz) 137 continue; 138 int t = mat[mp(x, y)]; 139 if(!t) 140 continue; 141 ans[t]++; 142 } 143 } 144 dfs3(0); 145 ask(0); 146 for(int i = 1; i <= q; i++) 147 printf("%d ", ans[yl[i]]); 148 return 0; 149 }
以上是关于bzoj 3351 [ioi2009]Regions的主要内容,如果未能解决你的问题,请参考以下文章