标签:bzoj bzoj3435 动态树分治 替罪羊树 treap
题目大意:给定一棵树,每次添加一个节点并询问当前有多少点对满足dis(i,j)<=ri+rj 强制在线
吾辈有生之年终于把这道题切了。。。QAQ
什么?你想做这题?
1095切了么?没?去把1095切掉再说!
3065切了么?没?去把3065切掉再说!
什么?都切了?那还不会做这题??
……
算了还是说说做法吧。。。
我们抛开那些乱七八糟的,考虑朴素做法
首先式子的形式是dis(i,j)<=ri+rj,令p=lca(i,j),把式子变形可以得到dis(j,p)-rj<=ri-dis(i,p)
那么对于每个p我们维护一个Treap,把以p为根的子树中所有的dis(j,p)-rj全都扔进去
然后对于每个i,我们沿着父亲指针扫一遍,把路径上所有Treap中小于等于ri-dis(i,p)的点全都计入答案,然后把dis(i,p)-ri扔进去
但是这样会有重复的,即lca(i,j)!=p的情况,那么我们对于p的每个子树再维护一个Treap储存dis(j,p)-rj,从对应子树的Treap中减掉这样的点对就行了
这不会TLE+MLE?
废话这当然会TLE+MLE。。。
考虑树的形态是一条链的时候,时间复杂度会退化为O(n^2logn),空间复杂度也会退化到O(n^2)。
那么我们可以考虑替罪羊树的思想,即如果某个子树的大小超过了父亲节点为根的子树大小的0.88,就把以父亲节点为根的子树暴力重建
既然要重建肯定要建成相对平衡一些的树辣。。。 于是点分治不就好了辣。。。。
说起来真是简单呢~~
于是这题我写了整整七个小时。。。写到后半夜两点才过掉。。。
主要是重建之后新的子树与原先的父节点连接很不好。。。
我が生涯に、一片の悔いなし。。。
#include <set> #include <queue> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define M 100100 #define ALPHA 0.88 using namespace std; int n; long long last_ans; int r[M]; namespace Graph{ struct abcd{ int to,f,next; int ban; }table[M<<1]; int head[M],tot=1; int ancestor[M][17],dpt[M],dis[M]; void Add(int x,int y,int z) { table[++tot].to=y; table[tot].f=z; table[tot].next=head[x]; head[x]=tot; } void Build_LCA(int x) { int j; for(j=1;j<=16;j++) ancestor[x][j]=ancestor[ancestor[x][j-1]][j-1]; } int LCA(int x,int y) { int j; if(dpt[x]<dpt[y]) swap(x,y); for(j=16;~j;j--) if(dpt[ancestor[x][j]]>=dpt[y]) x=ancestor[x][j]; if(x==y) return x; for(j=16;~j;j--) if(ancestor[x][j]!=ancestor[y][j]) x=ancestor[x][j],y=ancestor[y][j]; return ancestor[x][0]; } int Distance(int x,int y) { int lca=LCA(x,y); return dis[x]+dis[y]-2*dis[lca]; } } struct Treap{ static queue<Treap*> bin; Treap *ls,*rs; int val,key; int cnt,size; void* operator new (size_t,int _) { Treap *re; if(bin.size()) re=bin.front(),bin.pop(); else { static Treap *mempool,*C; if(C==mempool) mempool=(C=new Treap[1<<16])+(1<<16); re=C++; } re->ls=re->rs=0x0; re->val=_;re->key=rand();//信仰! re->cnt=re->size=1; return re; } void operator delete (void *p) { bin.push((Treap*)p); } void Push_Up() { size=cnt; if(ls) size+=ls->size; if(rs) size+=rs->size; } friend void Zig(Treap *&x) { Treap *y=x->ls; x->ls=y->rs; y->rs=x;x=y; x->rs->Push_Up(); x->Push_Up(); } friend void Zag(Treap *&x) { Treap *y=x->rs; x->rs=y->ls; y->ls=x;x=y; x->ls->Push_Up(); x->Push_Up(); } friend void Insert(Treap *&x,int y) { if(!x) { x=new (y)Treap; return ; } if(y==x->val) x->cnt++; else if(y<x->val) { Insert(x->ls,y); if(x->ls->key>x->key) Zig(x); } else { Insert(x->rs,y); if(x->rs->key>x->key) Zag(x); } x->Push_Up(); } friend void Decomposition(Treap *&x) { if(!x) return ; Decomposition(x->ls); Decomposition(x->rs); delete x;x=0x0; } friend int Query(Treap *x,int y) { if(!x) return 0; if(y<x->val) return Query(x->ls,y); else return (x->ls?x->ls->size:0) + x->cnt + Query(x->rs,y); } }; queue<Treap*> Treap :: bin; namespace Dynamic_TDC{ using namespace Graph; int fa[M],v[M],T; Treap *tree1[M],*tree2[M]; set<int> to[M]; void DFS(int x) { set<int>::iterator it; v[x]=T; for(it=to[x].begin();it!=to[x].end();it++) { DFS(*it); Decomposition(tree2[*it]); } to[x].clear(); Decomposition(tree1[x]); } int Get_Size(int x,int from) { int i,re=1; for(i=head[x];i;i=table[i].next) { if(v[table[i].to]!=T) continue; if(table[i].ban==T) continue; if(table[i].to==from) continue; re+=Get_Size(table[i].to,x); } return re; } int Get_Centre_Of_Gravity(int x,int from,int size,int &cg) { int i,re=1,flag=true; for(i=head[x];i;i=table[i].next) { if(v[table[i].to]!=T) continue; if(table[i].ban==T) continue; if(table[i].to==from) continue; int temp=Get_Centre_Of_Gravity(table[i].to,x,size,cg); if(temp<<1>size) flag=false; re+=temp; } if(size-re<<1>size) flag=false; if(flag) cg=x; return re; } void DFS(int x,int from,int dpt,Treap *&p) { int i; Insert(p,dpt-r[x]); for(i=head[x];i;i=table[i].next) { if(v[table[i].to]!=T) continue; if(table[i].ban==T) continue; if(table[i].to==from) continue; DFS(table[i].to,x,dpt+table[i].f,p); } } int Tree_Divide_And_Conquer(int x) { int i,size=Get_Size(x,0); Get_Centre_Of_Gravity(x,0,size,x); DFS(x,0,0,tree1[x]); for(i=head[x];i;i=table[i].next) { if(v[table[i].to]!=T) continue; if(table[i].ban==T) continue; Treap *p=0x0; DFS(table[i].to,x,table[i].f,p); table[i].ban=table[i^1].ban=T; int temp=Tree_Divide_And_Conquer(table[i].to); tree2[temp]=p;fa[temp]=x;to[x].insert(temp); } return x; } void Rebuild(int x) { ++T;DFS(x); int y=fa[x]; Treap *p=tree2[x]; tree2[x]=0x0; int temp=Tree_Divide_And_Conquer(x); fa[temp]=y;if(y) to[y].insert(temp); tree2[temp]=p; } void Insert(int x) { int i; for(i=x;i;i=fa[i]) { if(fa[i]) { int d1=Distance(x,fa[i]); last_ans+=Query(tree1[fa[i]],r[x]-d1); last_ans-=Query(tree2[i],r[x]-d1); Insert(tree2[i],d1-r[x]); } int d=Distance(x,i); Insert(tree1[i],d-r[x]); } //前方野生替罪咩预警! int to_rebuild=0; for(i=x;fa[i];i=fa[i]) if( (double)tree1[i]->size/tree1[fa[i]]->size > ALPHA ) to_rebuild=fa[i]; if(to_rebuild) Rebuild(to_rebuild); } } int main() { #ifndef ONLINE_JUDGE freopen("3435.in","r",stdin); freopen("3435.out","w",stdout); #endif srand(19980402);//我様は最強ね!にゃんははははは!~! int i,x,y,z; scanf("%*d%d",&n); for(i=1;i<=n;i++) { scanf("%d%d%d",&x,&y,&z); #ifdef ONLINE_JUDGE x=x^(last_ans%1000000000); #endif Graph::Add(i,x,y); Graph::Add(x,i,y); Graph::ancestor[i][0]=x; Graph::dpt[i]=Graph::dpt[x]+1; Graph::dis[i]=Graph::dis[x]+y; Graph::Build_LCA(i); r[i]=z; Dynamic_TDC::to[x].insert(i); Dynamic_TDC::fa[i]=x; Dynamic_TDC::Insert(i); #ifdef ONLINE_JUDGE printf("%lld\n",last_ans); #else printf("%I64d\n",last_ans); #endif } }
BZOJ 3435 Wc2014 紫荆花之恋 动态树分治+替罪羊树+Treap
标签:bzoj bzoj3435 动态树分治 替罪羊树 treap
原文地址:http://blog.csdn.net/popoqqq/article/details/44489859