1. 程式人生 > >[WC2014]紫荊花之戀(動態點分治+替罪羊思想)

[WC2014]紫荊花之戀(動態點分治+替罪羊思想)

父親 愛的 amp spa ans 有一個 cto bsp print

題目描述 強強和萌萌是一對好朋友。有一天他們在外面閑逛,突然看到前方有一棵紫荊樹。這已經是紫荊花飛舞的季節了,無數的花瓣以肉眼可見的速度從紫荊樹上長了出來。仔細看看的話,這個大樹實際上是一個帶權樹。每個時刻它會長出一個新的葉子節點。每個節點上有一個可愛的小精靈,新長出的節點上也會同時出現一個新的小精靈。小精靈是很萌但是也很脆弱的生物,每個小精靈 i 都有一個感受能力值Ri ,小精靈 i, j 成為朋友當且僅當在樹上 i 和 j 的距離 dist(i,j) ≤ Ri + Rj,其中 dist(i, j)表示在這個樹上從 i 到 j 的唯一路徑上所有邊的邊權和。強強和萌萌很好奇每次新長出一個葉子節點之後,這個樹上總共有幾對朋友。 我們假定這個樹一開始為空,節點按照加入的順序從 1開始編號。由於強強非常好奇, 你必須在他每次出現新節點後馬上給出總共的朋友對數,不能拖延哦。 題解
先考慮給定一棵靜態的樹,這道題怎麽做,顯然這是經典的點分治分題,假設當前分治中心為u,對於一個點對ij產生貢獻時,當且僅當dis[i]+dis[j]<=r[i]+r[j] -> dis[i]-r[i]<=r[j]-dis[j],我們考慮用平衡樹維護所有的dis[i]-r[i]然後用r[i]-dis[i]在平衡樹中查有多個數小於等於它就可以了。 那麽問題來了,這棵樹是動態的,怎麽維護。 考慮暴力,每次新建一個點,連一條邊,我們可以把原樹想象成一顆點分樹,每次從新增節點一直往上跳,邊跳邊更新,這樣的話可以過掉小規模的數據和隨機生成的數據。 因為這樣做樹高會被卡成O(n)的,所以不能過。 接下來,我們可以利用替罪羊的思想,每次搞完之後自上而下檢查一下,如果發現不平衡,就重構這棵點分樹,復雜度同替罪羊樹。 實現細節
聽起來感覺還可做,實現起來*&¥¥%%¥。 說一下我的具體做法。 在點分樹上的每個節點維護這些信息:該點分樹內的所有節點到這個點的距離(平衡樹),該點分樹內所有點到該點在點分樹上的父親的距離(平衡樹),該子樹所有點的集合(vector),該點到點分樹根的一條鏈(vector)。 每次新增的答案就是當前子樹的答案-小子樹的答案(其實就是減掉不合法的)。 重構細節很多,註意平衡樹的內存回收。 代碼
#include<iostream>
#include<cstdio>
#include<vector>
#include<cstdlib>
#define
ls tr[p].l #define rs tr[p].r #define N 100002 using namespace std; typedef long long ll; int topp,q[N*32],cnt,head[N],tot,p[N][20],dep[N],size[N],siz[N],dp[N],sum,root,rt[N],n,st[N],top,T[N]; ll deep[N],dis[N],r[N],ans; bool vis[N],tag[N]; vector<int>vec[N],E[N]; struct edge{int n,to;ll l;}e[N<<1]; inline void add(int u,int v,ll l){e[++tot].n=head[u];e[tot].to=v;head[u]=tot;e[tot].l=l;} const double pha=0.75; const int mod=1e9; struct node{int size,cnt,l,r,rd;ll val;}tr[N*32]; inline void pushup(int p){tr[p].size=tr[ls].size+tr[rs].size+tr[p].cnt;} inline int newnode(ll x){ int y=topp?q[topp--]:++cnt; tr[y].l=tr[y].r=0;tr[y].val=x;tr[y].rd=rand();tr[y].size=tr[y].cnt=1; return y; } inline void re(int x){q[++topp]=x;} inline void lturn(int &p){ int x=tr[p].r;tr[p].r=tr[x].l;tr[x].l=p; tr[x].size=tr[p].size;pushup(p);p=x; } inline void rturn(int &p){ int x=tr[p].l;tr[p].l=tr[x].r;tr[x].r=p; tr[x].size=tr[p].size;pushup(p);p=x; } inline void ins(int &p,ll x){ if(!p){p=newnode(x);return;} tr[p].size++; if(tr[p].val==x){tr[p].cnt++;return;} if(x>tr[p].val){ ins(rs,x); if(tr[p].rd>tr[rs].rd)lturn(p); } else{ ins(ls,x); if(tr[p].rd>tr[ls].rd)rturn(p); } } inline ll get_rank(int p,ll x){ if(!p)return 0; if(tr[p].val<=x)return tr[ls].size+tr[p].cnt+get_rank(rs,x); return get_rank(ls,x); } void bl(int p){if(ls)bl(ls);printf("%lld ",tr[p].val);if(rs)bl(rs);} inline ll rd(){ int x=0;char c=getchar();bool f=0; while(!isdigit(c)){if(c==-)f=1;c=getchar();} while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();} return f?-x:x; } inline int getlca(int a,int b){ if(dep[a]<dep[b])swap(a,b); for(int i=18;i>=0;--i)if(dep[a]-(1<<i)>=dep[b])a=p[a][i]; if(a==b)return a; for(int i=18;i>=0;--i)if(p[a][i]!=p[b][i])a=p[a][i],b=p[b][i]; return p[a][0]; } inline ll dist(int a,int b){return dis[a]+dis[b]-2*dis[getlca(a,b)];} void getsize(int u,int fa){ siz[u]=1; for(int i=head[u];i;i=e[i].n)if(e[i].to!=fa&&vis[e[i].to]&&!tag[e[i].to]){ int v=e[i].to;getsize(v,u);siz[u]+=siz[v]; } } void getroot(int u,int fa){ dp[u]=0;siz[u]=1; for(int i=head[u];i;i=e[i].n)if(vis[e[i].to]&&e[i].to!=fa&&!tag[e[i].to]){ int v=e[i].to;getroot(v,u); siz[u]+=siz[v];dp[u]=max(dp[u],siz[v]); } dp[u]=max(sum-siz[u],dp[u]); if(dp[u]<dp[root])root=u; } void getdeep(int u,int fa,int top,int tt){ ins(rt[top],deep[u]-r[u]);E[top].push_back(u); ins(T[tt],deep[u]-r[u]);vec[u].push_back(top); size[top]++; for(int i=head[u];i;i=e[i].n)if(e[i].to!=fa&&vis[e[i].to]&&!tag[e[i].to]){ int v=e[i].to;deep[v]=deep[u]+e[i].l; getdeep(v,u,top,tt); } } void solve(int u){ tag[u]=1; size[u]=1;E[u].push_back(u); ins(rt[u],-r[u]); for(int i=head[u];i;i=e[i].n)if(vis[e[i].to]&&!tag[e[i].to]){ int v=e[i].to; sum=siz[v];root=n+1; getroot(v,u);getsize(root,0); deep[v]=e[i].l;getdeep(v,u,u,root); solve(root); } } void efs(int p){if(!p)return;if(ls)efs(ls);if(rs)efs(rs);re(p);} inline void rebuild(int u){ int ma=E[u].size(); for(int i=0;i<ma;++i){ int v=E[u][i]; st[++top]=v;vis[v]=1; } ma=vec[u].size(); int king=ma?vec[u].back():0; for(int i=1;i<=top;++i){ int x=st[i];size[x]=0; E[x].clear(); while(vec[x].size()&&vec[x].back()!=king)vec[x].pop_back(); efs(rt[x]);efs(T[x]);rt[x]=T[x]=0; } root=n+1;sum=top;dp[root]=n+1; getroot(u,0);getsize(root,0);int haha=root; solve(root); if(king){ for(int i=1;i<=top;++i){ int x=st[i]; ll d=dist(x,king); ins(T[haha],d-r[x]); } } while(top){ int x=st[top]; vis[st[top]]=0; tag[st[top]]=0; top--; } } inline void check(int u){ int ma=vec[u].size(); for(int i=1;i<ma;++i){ int v=vec[u][i],v1=vec[u][i-1]; if(size[v1]*pha<size[v]){ rebuild(v1); break; } } } inline void work(int u,int fa){ int ma=vec[fa].size(); for(int i=0;i<ma;++i)vec[u].push_back(vec[fa][i]); vec[u].push_back(fa); ins(rt[u],-r[u]);size[u]=1;E[u].push_back(u); ma++; for(int i=ma-1;i>=0;--i){ int v=vec[u][i];ll d=dist(u,v); size[v]++;E[v].push_back(u); int nex=i==ma-1?u:vec[u][i+1]; ins(rt[v],d-r[u]);ins(T[nex],d-r[u]); ans+=get_rank(rt[v],r[u]-d)-get_rank(T[nex],r[u]-d); } check(u); } int main(){ srand(3783252); n=rd();n=rd(); ll a=rd(),c=rd();r[1]=rd(); size[1]=1;ins(rt[1],-r[1]); E[1].push_back(1); printf("%lld\n",ans); for(int i=2;i<=n;++i){ a=rd();c=rd();r[i]=rd(); a=a^(ans%mod); add(i,a,c);add(a,i,c); dep[i]=dep[a]+1;dis[i]=dis[a]+c;p[i][0]=a; for(int j=1;(1<<j)<=dep[i];++j)p[i][j]=p[p[i][j-1]][j-1]; work(i,a); printf("%lld\n",ans); } return 0; }  

[WC2014]紫荊花之戀(動態點分治+替罪羊思想)