#55. WC2014紫荆花之恋

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了#55. WC2014紫荆花之恋相关的知识,希望对你有一定的参考价值。

强强和萌萌是一对好朋友。有一天他们在外面闲逛,突然看到前方有一棵紫荆树。这已经是紫荆花飞舞的季节了,无数的花瓣以肉眼可见的速度从紫荆树上长了出来。

仔细看看的话,这个大树实际上是一个带权树。每个时刻它会长出一个新的叶子节点,每个节点上有一个可爱的小精灵,新长出的节点上也会同时出现一个新的小精灵。小精灵是很萌但是也很脆弱的生物,每个小精灵 ii 都有一个感受能力值 riri,小精灵 i,ji,j 成为朋友当且仅当在树上 ii 和 jj 的距离 dist(i,j)ri+rjdist(i,j)≤ri+rj,其中 dist(i,j)dist(i,j) 表示在这个树上从 ii 到 jj 的唯一路径上所有边的边权和。

强强和萌萌很好奇每次新长出一个叶子节点之后,这个树上总共有几对朋友。

我们假定这个树一开始为空,节点按照加入的顺序从 11 开始编号。由于强强非常好奇,你必须在他每次出现新结点后马上给出总共的朋友对数,不能拖延哦。

输入格式

第一行包含一个整数,表示测试点编号。

第二行包含一个正整数 nn,表示总共要加入的节点数。

我们令加入节点前的总共朋友对数是 last_anslast_ans,在一开始时它的值为 00。

接下来 nn 行中第 ii 行有三个非负整数 ai,ci,riai,ci,ri,表示结点 ii 的父节点的编号为 aixor(last_ansmod109)aixor(last_ansmod109)(其中 xorxor 表示异或,modmod表示取余,数据保证这样操作后得到的结果介于 11到 i1i−1 之间),与父结点之间的边权为 cici,节点 ii 上小精灵的感受能力值为 riri。

注意 a1=c1=0a1=c1=0,表示 11 号节点是根结点,对于 i>1i>1,父节点的编号至少为 11。

输出格式

包含 nn 行,每行输出 11 个整数,表示加入第 ii 个点之后,树上有几对朋友。

样例一

input

0
5
0 0 6
1 2 4
0 9 4
0 5 5
0 2 4

output

0
1
2
4
7

样例二

见样例数据下载。

限制与约定

对于所有数据,满足 1ci100001≤ci≤10000,ai2×109ai≤2×109,ri109ri≤109。

测试点编号约定
1, 2 n100n≤100
3, 4 n1000n≤1000
5, 6, 7, 8 n100000n≤100000,节点 11 最多有两个子节点,其它节点最多有一个子节点
9, 10 n100000n≤100000,ri10ri≤10
11, 12 n100000n≤100000,这棵树是随机生成的
13, 14, 15 n70000n≤70000
16, 17, 18, 19, 20 n100000n≤100000

此题 hack 时忽略输入数据中给定的测试点编号对测试点的限制。

祝大家一遍 AC,求不虐萌萌哒测评机!

时间限制12s12s

空间限制512MB

  1 #include <set>  
  2 #include <queue>  
  3 #include <cstdio>  
  4 #include <cstring>  
  5 #include <iostream>  
  6 #include <algorithm>  
  7 #define M 100100  
  8 #define ALPHA 0.88  
  9 using namespace std;  
 10   
 11 int n;  
 12 long long last_ans;  
 13 int r[M];  
 14   
 15 namespace Graph{  //我们把这棵树除了构建点分树之外再构建一棵根为1的树,用来查询两点之间的距离 
 16    
 17     struct abcd{  
 18         int to,f,next; //终点,边权,下一条边 
 19         int ban;  //这条边能不能走(会不会走出这棵子树) 
 20     }table[M<<1];  //边表 
 21     int head[M]/*每个点的邻接表*/,tot=1/*边数*/;  
 22   
 23     int ancestor[M][17]/*表示x向上2^j的祖先 */,dpt[M]/*深度*/,dis[M]/*走到根的路径权值和*/;  
 24   
 25     void Add(int x,int y,int z)  //加边 
 26     {  
 27         table[++tot].to=y;  
 28         table[tot].f=z;  
 29         table[tot].next=head[x];  
 30         head[x]=tot;  
 31     }  
 32   
 33     void Build_LCA(int x)  //构建 ancestor[x][j]表示x向上2^j的祖先 
 34     {  
 35         int j;  
 36         for(j=1;j<=16;j++)  
 37             ancestor[x][j]=ancestor[ancestor[x][j-1]][j-1];  
 38     }  
 39   
 40     int LCA(int x,int y)  //求lca 
 41     {  
 42         int j;  
 43         if(dpt[x]<dpt[y])  
 44             swap(x,y);  
 45         for(j=16;~j;j--)  
 46             if(dpt[ancestor[x][j]]>=dpt[y])  
 47                 x=ancestor[x][j];  
 48         if(x==y) return x;  
 49         for(j=16;~j;j--)  
 50             if(ancestor[x][j]!=ancestor[y][j])  
 51                 x=ancestor[x][j],y=ancestor[y][j];  
 52         return ancestor[x][0];  
 53     }  
 54   
 55     int Distance(int x,int y)  //求两点距离 
 56     {  
 57         int lca=LCA(x,y);  
 58         return dis[x]+dis[y]-2*dis[lca];  
 59     }  
 60   
 61 }  
 62   
 63 struct Treap{  
 64   
 65     static queue<Treap*> bin;  //垃圾桶,用来写垃圾回收 
 66       
 67     Treap *ls,*rs;  //左右子树 
 68     int val,key;  //键值,优先级 
 69     int cnt,size;  //cnt表示这个数的个数,size表示这个点子树的大小 
 70   
 71     void* operator new (size_t,int _)  
 72     {  
 73         Treap *re;  
 74         if(bin.size())  
 75             re=bin.front(),bin.pop();  
 76         else  
 77         {  
 78             static Treap *mempool,*C;  
 79             if(C==mempool)  
 80                 mempool=(C=new Treap[1<<16])+(1<<16);  
 81             re=C++;  
 82         }  
 83         re->ls=re->rs=0x0;  
 84         re->val=_;re->key=rand();//信仰!  
 85         re->cnt=re->size=1;  
 86         return re;  
 87     }  
 88   
 89     void operator delete (void *p)  
 90     {  
 91         bin.push((Treap*)p);  
 92     }  
 93   
 94     void Push_Up()  //maintain
 95     {  
 96         size=cnt;  
 97         if(ls) size+=ls->size;  
 98         if(rs) size+=rs->size;  
 99     }  
100   
101     friend void Zig(Treap *&x)  
102     {  
103         Treap *y=x->ls;  
104         x->ls=y->rs;  
105         y->rs=x;x=y;  
106         x->rs->Push_Up();  
107         x->Push_Up();  
108     }  
109   
110     friend void Zag(Treap *&x)  
111     {  
112         Treap *y=x->rs;  
113         x->rs=y->ls;  
114         y->ls=x;x=y;  
115         x->ls->Push_Up();  
116         x->Push_Up();  
117     }  
118   
119     friend void Insert(Treap *&x,int y)  
120     {  
121         if(!x)  
122         {  
123             x=new (y)Treap;  
124             return ;  
125         }  
126         if(y==x->val)  
127             x->cnt++;  
128         else if(y<x->val)  
129         {  
130             Insert(x->ls,y);  
131             if(x->ls->key>x->key)  
132                 Zig(x);  
133         }  
134         else  
135         {  
136             Insert(x->rs,y);  
137             if(x->rs->key>x->key)  
138                 Zag(x);  
139         }  
140         x->Push_Up();  
141     }  
142   
143     friend void Decomposition(Treap *&x)  //删除整棵树 
144     {  
145         if(!x) return ;  
146         Decomposition(x->ls);  
147         Decomposition(x->rs);  
148         delete x;x=0x0;  
149     }  
150   
151     friend int Query(Treap *x,int y)  //求比y小的数的个数 
152     {  
153         if(!x) return 0;  
154         if(y<x->val)  
155             return Query(x->ls,y);  
156         else  
157             return (x->ls?x->ls->size:0) + x->cnt + Query(x->rs,y);  
158     }  
159   
160 };  
161   
162 queue<Treap*> Treap :: bin;  
163   
164 namespace Dynamic_TDC{  
165   
166     using namespace Graph;  
167   
168     int fa[M]/*点分树上的fa*/,v[M],T;  
169   
170     Treap *tree1[M]/*这个点集所有点的权值构成的treap*/,*tree2[M]/*这个点集一棵子树的权值构成的treap*/;  
171   
172     set<int> to[M];  //点分树上的儿子 
173       
174     void DFS(int x)  //删除整棵子树(这里指点分树上的子树) 
175     {  
176         set<int>::iterator it;  
177         v[x]=T;  
178         for(it=to[x].begin();it!=to[x].end();it++)  //枚举点分树上的所有儿子 
179         {  
180             DFS(*it);  
181             Decomposition(tree2[*it]);  
182         }  
183         to[x].clear();  
184         Decomposition(tree1[x]);  
185     }  
186   
187     int Get_Size(int x,int from)  //求树的大小 
188     {  
189         int i,re=1;  
190         for(i=head[x];i;i=table[i].next)  //遍历从这个点出发的每条边 
191         {  
192             if(v[table[i].to]!=T)  
193                 continue;  
194             if(table[i].ban==T)  
195                 continue;  
196             if(table[i].to==from)  
197                 continue;  //记录上一个点,这个点不能回到上一个点 
198             re+=Get_Size(table[i].to,x);  
199         }  
200         return re;  
201     }  
202   
203     int Get_Centre_Of_Gravity(int x,int from,int size,int &cg)  //求重心 
204     {  
205         int i,re=1,flag=true;  
206         for(i=head[x];i;i=table[i].next)  //遍历从这个点出发的每条边 
207         {  
208             if(v[table[i].to]!=T)  
209                 continue;  
210             if(table[i].ban==T)  
211                 continue;  
212             if(table[i].to==from)  
213                 continue;  //记录上一个点,这个点不能回到上一个点 
214             int temp=Get_Centre_Of_Gravity(table[i].to,x,size,cg);  
215             if(temp<<1>size) flag=false;  
216             re+=temp;   
217         }  
218         if(size-re<<1>size) flag=false;  
219         if(flag) cg=x;  
220         return re;  
221     }  
222   
223     void DFS(int x,int from,int dpt,Treap *&p)  //把所有在这棵子树的dep[x]-r[x]插入到treap中 
224     {  
225         int i;  
226         Insert(p,dpt-r[x]);  
227         for(i=head[x];i;i=table[i].next)  
228         {  
229             if(v[table[i].to]!=T)  
230                 continue;  
231             if(table[i].ban==T)  
232                 continue;  
233             if(table[i].to==from)  
234                 continue;  
235             DFS(table[i].to,x,dpt+table[i].f,p);  
236         }  
237     }  
238       
239     int Tree_Divide_And_Conquer(int x)  //点分 
240     {  
241         int i,size=Get_Size(x,0);  //得到整棵树的size 
242         Get_Centre_Of_Gravity(x,0,size,x);  //得到重心,在这之后x为根 
243         DFS(x,0,0,tree1[x]);  //把所有在这棵子树的dep[x]-r[x]插入到treap中
244         for(i=head[x];i;i=table[i].next)  
245         {  
246             if(v[table[i].to]!=T)  
247                 continue;  
248             if(table[i].ban==T)  
249                 continue;  
250               
251             Treap *p=0x0;  
252             DFS(table[i].to,x,table[i].f,p);  //把所有在这棵子树的dep[x]-r[x]插入到treap中
253               
254             table[i].ban=table[i^1].ban=T;  //这条边会通向上一个分治中心,如果走了这条边就会走到外面 
255               
256             int temp=Tree_Divide_And_Conquer(table[i].to);  //分治,递归各子树,temp为各子树的重心 
257             tree2[temp]=p;fa[temp]=x;/*不是树上的fa,是点分树上的fa*/to[x].insert(temp);  
258         }  
259         return x;  
260     }  
261   
262     void Rebuild(int x)  
263     {  
264         ++T;/*新建点分树上的节点*/DFS(x);  //把x的子树直接整棵删除 
265         int y=fa[x];  //得到点分树上的父亲 
266         Treap *p=tree2[x];  //tree2是以y为根时x这个点集的dep[i]-r[i]所构成的treap,所以不会改变,应当保留 
267         tree2[x]=0x0;  
268         int temp=Tree_Divide_And_Conquer(x);   //重新点分之后的节点 (重构后的这棵点分树的子树的根)
269         fa[temp]=y;if(y) to[y].insert(temp);  //此处因为不仅要插入新的子节点,还要把原来的删掉,所以要加一句to[y].erase(x); 
270         tree2[temp]=p;  //保留原来的tree2 
271     }  
272   
273     void Insert(int x)  //在点分树上插入新节点x 
274     {  
275         int i;  
276           
277         for(i=x;i;i=fa[i])  //找到点分树上x所在的所有点集 
278         {  
279   
280             if(fa[i])  //如果有上一层的点分树 
281             {  
282                 int d1=Distance(x,fa[i]);  
283                 last_ans+=Query(tree1[fa[i]],r[x]-d1);  
284                 last_ans-=Query(tree2[i],r[x]-d1);//计算上一层的点分树会带来多少收益  
285                 Insert(tree2[i],d1-r[x]);  //并在以fa[i]为根的树中i这棵子树的treap中插入关于x的信息 
286             }  
287   
288             int d=Distance(x,i);  
289             Insert(tree1[i],d-r[x]);  //在以i为根的这个点集的treap中插入关于x的信息 
290               
291         }  
292   
293         //前方野生替罪咩预警!  
294   
295         int to_rebuild=0;  
296   
297         for(i=x;fa[i];i=fa[i])  
298             if( (double)tree1[i]->size/tree1[fa[i]]->size > ALPHA )  //如果一个节点(fa[i])的子树不满足替罪羊树的性质 (有一个子树太大了) 
299                 to_rebuild=fa[i];  //保证找到的是点分树上深度最浅的节点 ,由于如果重建了深度最浅的节点,就等于重建了它的整棵子树,所以它子树的节点自然不需要重建 
300   
301         if(to_rebuild)  
302             Rebuild(to_rebuild);  
303     }  
304   
305 }  
306 int main()  
307 {  
308     #ifndef ONLINE_JUDGE  
309     freopen("3435.in","r",stdin);  
310     freopen("3435.out","w",stdout);  
311     #endif  
312       
313     srand(19980402);//我様は最強ね!にゃんははははは!~!  
314     int i,x,y,z;  
315     scanf("%*d%d",&n);  
316     for(i=1;i<=n;i++)  
317     {  
318         scanf("%d%d%d",&x,&y,&z);  
319         #ifdef ONLINE_JUDGE  
320         x=x^(last_ans%1000000000);  
321         #endif  
322   
323         Graph::Add(i,x,y);  
324         Graph::Add(x,i,y);  
325         Graph::ancestor[i][0]=x;  
326         Graph::dpt[i]=Graph::dpt[x]+1;  
327         Graph::dis[i]=Graph::dis[x]+y;  
328         Graph::Build_LCA(i);  
329         r[i]=z;  //更新原树(即以1为根,用来查询两点距离的树) 
330   
331         Dynamic_TDC::to[x].insert(i);  
332         Dynamic_TDC::fa[i]=x;  
333         Dynamic_TDC::Insert(i);  //在点分树上插入只有i这个点的点集 
334   
335         #ifdef ONLINE_JUDGE  
336             printf("%lld\n",last_ans);  
337         #else  
338             printf("%I64d\n",last_ans);  
339         #endif  
340     }  
341 }  

 

以上是关于#55. WC2014紫荆花之恋的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ3435 & 洛谷3920 & UOJ55:[WC2014]紫荆花之恋

BZOJ 3435: [Wc2014]紫荆花之恋

[WC 2014]紫荆花之恋

BZOJ3435[Wc2014]紫荆花之恋 替罪点分树+SBT

Wc2014 紫荆花之恋

[WC2014]紫荆花之恋