#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到 i−1i−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
样例二
见样例数据下载。
限制与约定
对于所有数据,满足 1≤ci≤100001≤ci≤10000,ai≤2×109ai≤2×109,ri≤109ri≤109。
测试点编号 | 约定 |
---|---|
1, 2 | n≤100n≤100 |
3, 4 | n≤1000n≤1000 |
5, 6, 7, 8 | n≤100000n≤100000,节点 11 最多有两个子节点,其它节点最多有一个子节点 |
9, 10 | n≤100000n≤100000,ri≤10ri≤10 |
11, 12 | n≤100000n≤100000,这棵树是随机生成的 |
13, 14, 15 | n≤70000n≤70000 |
16, 17, 18, 19, 20 | n≤100000n≤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]紫荆花之恋