BZOJ3435[Wc2014]紫荆花之恋 替罪点分树+SBT
Posted CQzhangyu
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ3435[Wc2014]紫荆花之恋 替罪点分树+SBT相关的知识,希望对你有一定的参考价值。
【BZOJ3435】[Wc2014]紫荆花之恋
Description
强强和萌萌是一对好朋友。有一天他们在外面闲逛,突然看到前方有一棵紫荆树。这已经是紫荆花飞舞的季节了,无数的花瓣以肉眼可见的速度从紫荆树上长了出来。仔细看看的话,这个大树实际上是一个带权树。每个时刻它会长出一个新的叶子节点。每个节点上有一个可爱的小精灵,新长出的节点上也会同时出现一个新的小精灵。小精灵是很萌但是也很脆弱的生物,每个小精灵 i 都有一个感受能力值Ri ,小精灵 i, j 成为朋友当且仅当在树上 i 和 j 的距离 dist(i,j) ≤ Ri + R! ,其中 dist(i, j)表示在这个树上从 i 到 j 的唯一路径上所有边的边权和。强强和萌萌很好奇每次新长出一个叶子节点之后,这个树上总共有几对朋友。
我们假定这个树一开始为空,节点按照加入的顺序从 1开始编号。由于强强非常好奇, 你必须在他每次出现新节点后马上给出总共的朋友对数,不能拖延哦。
Input
共有 n + 2 行。
第一行包含一个正整数,表示测试点编号。
第二行包含一个正整数 n ,表示总共要加入的节点数。
我们令加入节点前的总共朋友对数是 last_ans,在一开始时它的值为0。
接下来 n 行中第 i 行有三个数 ai, bi, ri,表示节点 i 的父节点的编号为 ai xor (last_ans mod 10^9) (其中xor 表示异或,mod 表示取余,数据保证这样操作后得到的结果介于 1到i – 1之间),与父节点之间的边权为 ci,节点 i 上小精灵的感受能力值为r!。
注意 a1 = c1 = 0,表示 1 号点是根节点,对于 i > 1,父节点的编号至少为1。
Output
包含 n 行,每行输出1 个整数, 表示加入第 i 个点之后,树上有几对朋友。
Sample Input
5
0 0 6
1 2 4
0 9 4
0 5 5
0 2 4
Sample Output
1
2
4
7
HINT
1<=Ci<=10000
Ai<=2*10^9
Ri<=10^9
N<=100000
题解:在GXZ的蛊惑下,特地去学了一发SBT~
显然要将题中的式子拆一下:dis(i,j)<=ri+rj -> dis(i,lca)+dis(j,lca)<=ri+rj -> dis(i,lca)-ri<=rj-dis(j,lca)。
所以我们对点分树上的每个节点都维护一个SBT记录所有dis(i,x)-ri,然后每次加点时,在点分树上到根的路径上的每个点的SBT都查一下就行了。由于有重复计算,所以对于每个点我们还要维护一个SBT记录所有dis(i,fa[x])-ri,查询时减去即可。
但是动态加点怎么办?将点分树变成替罪的即可。
其实代码并不是特别长,如果TLE了一定是写挂了~
#include <cstdio> #include <cstring> #include <iostream> #include <queue> using namespace std; typedef long long ll; const int maxn=100010; const ll mod=1000000000; int n,m,tot,cnt,mn,root; ll ans; struct sbt { int siz,ch[2],val; }t[20000005]; vector<int> ch[maxn]; int r[maxn],f[19][maxn],siz[maxn],dep[maxn],head[maxn],next[maxn<<1],to[maxn<<1],vis[maxn],p[maxn]; int r1[maxn],r2[maxn],fa[maxn],dd[maxn],Log[maxn]; queue<int> q; int mem; inline int rd() { int ret=0,f=1; char gc=getchar(); while(gc<‘0‘||gc>‘9‘) {if(gc==‘-‘)f=-f; gc=getchar();} while(gc>=‘0‘&&gc<=‘9‘) ret=ret*10+gc-‘0‘,gc=getchar(); return ret*f; } void pushup(int x) {t[x].siz=t[t[x].ch[0]].siz+t[t[x].ch[1]].siz+1;} void rotate(int &x,int d) { int y=t[x].ch[d]; t[x].ch[d]=t[y].ch[d^1],t[y].ch[d^1]=x; pushup(x),pushup(y),x=y; } void maintain(int &x,int d) { if(t[t[t[x].ch[d]].ch[d]].siz>t[t[x].ch[d^1]].siz) rotate(x,d); else if(t[t[t[x].ch[d]].ch[d^1]].siz>t[t[x].ch[d^1]].siz) rotate(t[x].ch[d],d^1),rotate(x,d); else return; maintain(t[x].ch[0],0),maintain(t[x].ch[1],1); maintain(x,0),maintain(x,1); } void insert(int &x,int y) { if(!x) { mem--; x=q.front(),q.pop(); t[x].siz=1,t[x].val=y,t[x].ch[0]=t[x].ch[1]=0; return ; } int d=(y>=t[x].val); t[x].siz++,insert(t[x].ch[d],y); maintain(x,d); } int query(int x,int y) { if(!x) return 0; if(t[x].val<=y) return query(t[x].ch[1],y)+1+t[t[x].ch[0]].siz; return query(t[x].ch[0],y); } void del(int &x) { if(!x) return ; mem++; del(t[x].ch[0]),del(t[x].ch[1]),t[x].siz=t[x].val=0,q.push(x),x=0; } void getrt(int x,int fa) { siz[x]=1; int i,tmp=0; for(i=head[x];i!=-1;i=next[i]) if(to[i]!=fa&&vis[to[i]]==2) getrt(to[i],x),siz[x]+=siz[to[i]],tmp=max(tmp,siz[to[i]]); tmp=max(tmp,tot-siz[x]); if(tmp<mn) mn=tmp,root=x; } void solve(int x) { vis[x]=1; for(int i=head[x];i!=-1;i=next[i]) if(vis[to[i]]==2) tot=siz[to[i]],mn=1<<30,getrt(to[i],x),fa[root]=x,solve(root); } void add(int a,int b) { to[cnt]=b,next[cnt]=head[a],head[a]=cnt++; } int lca(int a,int b) { if(dd[a]<dd[b]) swap(a,b); int i; for(i=Log[dd[a]-dd[b]];i>=0;i--) if(dd[f[i][a]]>=dd[b]) a=f[i][a]; if(a==b) return b; for(i=Log[dd[a]];i>=0;i--) if(f[i][a]!=f[i][b]) a=f[i][a],b=f[i][b]; return f[0][a]; } int dis(int a,int b) { return dep[a]+dep[b]-2*dep[lca(a,b)]; } int main() { rd(),n=rd(); memset(head,-1,sizeof(head)); int i,j,a,b,u,last,flast; mem=20000000; for(i=1;i<=20000000;i++) q.push(i); rd(),rd(),r[1]=rd(),siz[1]=1,dd[1]=1,ch[1].push_back(1),insert(r1[1],-r[1]); for(i=2;i<=n;i++) Log[i]=Log[i>>1]+1; printf("0\n"); for(i=2;i<=n;i++) { a=rd()^(ans%mod),b=rd(),r[i]=rd(); add(a,i),add(i,a),dep[i]=dep[a]+b,dd[i]=dd[a]+1; f[0][i]=a,fa[i]=a; for(j=1;j<=Log[dd[i]];j++) f[j][i]=f[j-1][f[j-1][i]]; for(last=0,u=i;u;u=fa[u]) { ans+=query(r1[u],r[i]-dis(i,u)); ch[u].push_back(i),insert(r1[u],dis(i,u)-r[i]),siz[u]++; if(fa[u]) { ans-=query(r2[u],r[i]-dis(i,fa[u])); insert(r2[u],dis(i,fa[u])-r[i]); } if(fa[u]&&siz[u]*1.0>(siz[fa[u]]+1)*0.88) last=fa[u]; } if(last) { flast=fa[last],vis[flast]=3; for(p[0]=j=0;j<(int)ch[last].size();j++) p[++p[0]]=ch[last][j]; for(j=1;j<=p[0];j++) ch[p[j]].clear(),del(r1[p[j]]),del(r2[p[j]]),vis[p[j]]=2; tot=p[0],mn=1<<30,getrt(last,0),fa[root]=flast,solve(root); for(j=1;j<=p[0];j++) { for(u=p[j];u!=flast;u=fa[u]) { ch[u].push_back(p[j]); insert(r1[u],dis(p[j],u)-r[p[j]]); if(fa[u]) insert(r2[u],dis(p[j],fa[u])-r[p[j]]); } } } printf("%lld\n",ans); } return 0; }
以上是关于BZOJ3435[Wc2014]紫荆花之恋 替罪点分树+SBT的主要内容,如果未能解决你的问题,请参考以下文章
BZOJ3435 & 洛谷3920 & UOJ55:[WC2014]紫荆花之恋