码迷,mamicode.com
首页 > 其他好文 > 详细

bzoj 3351 [ioi2009]Regions

时间:2019-04-15 20:04:41      阅读:104      评论:0      收藏:0      [点我收藏+]

标签:opened   region   pac   次数   end   alt   fine   vector   style   

N个节点的树,有R种属性,每个点属于一种属性。有Q次询问,每次询问r1,r2,回答有多少对(e1,e2)满足e1属性是r1,e2属性是r2,e1是e2的祖先。
数据规模
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

Sample Output

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\n", ans[yl[i]]);
148     return 0;
149 }
View Code

 

bzoj 3351 [ioi2009]Regions

标签:opened   region   pac   次数   end   alt   fine   vector   style   

原文地址:https://www.cnblogs.com/ZJXXCN/p/10712302.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!