您的位置:首页 > 其它

BZOJ3779: 重组病毒

2016-05-29 12:06 375 查看
题目大意:给一棵树,每个点一开始颜色互不相同,支持三个操作

                 1.将一个点到根的路径染成一种新的颜色

                 2.将一个新的点设为根,并将原来的根到这个点的路径染成一种新的颜色

                 3.查询一个子树(对于当前根)到根的路径期望颜色数

 

真TM是道神题,idea实在是太妙了

首先由于第2个操作的特殊性,我们可以发现,每种颜色在树上都是连续的,不会断开

于是第三个操作就变成了查询期望颜色段数

然后我们想象,如果一个点和他父亲结点的颜色不同,那就把他到他父亲的这条边权视为1,否则视为0

这样就变成了查询期望到根的路径和+1

然后我们看第一个操作对于这棵树上边权的影响:

这个点到根的路径全部变成0,与这条路径相邻的其他边都变成1

 

哇!太TM神奇了!

这是不是很像LCT的Access操作!

我们把边权为0的看做实边,边权为1的看做虚边,就和LCT一模一样

那么假设我们维护一个LCT,这样就可以在logn的时间内知道要修改哪些边权了!要修改的边的数量也是logn级别的!

于是我们可以在最开始树链剖分一下,用一颗线段树维护每个点到当前根的颜色段数

当修改一个边权的时候,相当于对这颗子树进行修改,那就在线段树上改一下就行了!

查询的时候,只需要用子树的和除以子树大小+1就好辣!

 

等等!

 

他还会换根?!那这子树怎么维护?!

其实也可以维护啦!如果做过“BZOJ3083 遥远的国度”就知道啦,只需要分类讨论一下就好了,当前的子树最多在原来的序列中被切成两段,不影响时间复杂度的!

 

具体可以看代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<ctime>
#define N 200010
using namespace std;
unsigned int to
,nxt
,pre
,cnt;
unsigned int root=1;
void ae(unsigned int ff,unsigned int tt)
{
cnt++;
to[cnt]=tt;
nxt[cnt]=pre[ff];
pre[ff]=cnt;
}
unsigned int Siz
,d
,zs
,FA
;
unsigned int fa
;
void build1(unsigned int x)
{
unsigned int i,j;
Siz[x]=1;
unsigned int maxn=0,maxb=0;
for(i=pre[x];i;i=nxt[i])
{
j=to[i];
if(j==fa[x]) continue;
FA[j]=fa[j]=x;
d[j]=d[x]+1;
build1(j);
Siz[x]+=Siz[j];
if(Siz[j]>maxn)
{
maxn=Siz[j];
maxb=j;
}
}
zs[x]=maxb;
}
unsigned int top
,sit
,fan
,cn;
void make(unsigned int x,unsigned int tt)
{
cn++;
sit[x]=cn;fan[cn]=x;
top[x]=tt;
if(zs[x]) make(zs[x],tt);
unsigned int i,j;
for(i=pre[x];i;i=nxt[i])
{
j=to[i];
if(j==zs[x]||j==fa[x]) continue;
make(j,j);
}
}
unsigned int GET(unsigned int x,unsigned int y)
{
while(top[y]!=top[x])
{
if(FA[top[y]]==x) return top[y];
y=FA[top[y]];
}
return fan[sit[x]+1];
}
unsigned int ch
[2],L
,R
;
unsigned int n,m;
bool rev
;
void pup(unsigned int x)
{
if(!ch[x][0]) L[x]=x;
else L[x]=L[ch[x][0]];
if(!ch[x][1]) R[x]=x;
else R[x]=R[ch[x][1]];
}
void pudrev(unsigned int x)
{
if(!x) return;
swap(ch[x][0],ch[x][1]);
swap(L[x],R[x]);
rev[x]^=1;
}
void pud(unsigned int x)
{
if(rev[x])
{
pudrev(ch[x][0]);
pudrev(ch[x][1]);
rev[x]=false;
}
}
bool isroot(unsigned int x)
{
return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;
}
void rotate(unsigned int x)
{
unsigned int y=fa[x],z=fa[y];
if(!isroot(y))
{
if(ch[z][0]==y) ch[z][0]=x;
else ch[z][1]=x;
}
unsigned int l=0,r;
if(ch[y][1]==x) l=1;r=l^1;
fa[ch[x][r]]=y;
fa[y]=x;
fa[x]=z;
ch[y][l]=ch[x][r];
ch[x][r]=y;
pup(y);//pup(x);
}
unsigned int q
,tt;
unsigned int l[N<<2],r[N<<2],sum[N<<2],t[N<<2];
void Pup(unsigned int x){sum[x]=sum[x<<1]+sum[x<<1|1];}
void Pud(unsigned int x)
{
if(!t[x]) return;
t[x<<1]+=t[x];t[x<<1|1]+=t[x];
sum[x<<1]+=(r[x<<1]-l[x<<1]+1)*t[x];
sum[x<<1|1]+=(r[x<<1|1]-l[x<<1|1]+1)*t[x];
t[x]=0;
}
void build(unsigned int now,unsigned int ll,unsigned int rr)
{
l[now]=ll;r[now]=rr;
if(ll==rr)
{
sum[now]=d[fan[ll]];
return;
}
unsigned int mid=(ll+rr)>>1;
build(now<<1,ll,mid);
build(now<<1|1,mid+1,rr);
Pup(now);
}
void change(unsigned int now,unsigned int ll,unsigned int rr,unsigned int v)
{
if(l[now]==ll&&r[now]==rr)
{
t[now]+=v;
sum[now]+=(r[now]-l[now]+1)*v;
return;
}
Pud(now);
unsigned int mid=(l[now]+r[now])>>1;
if(rr<=mid) change(now<<1,ll,rr,v);
else if(ll>mid) change(now<<1|1,ll,rr,v);
else change(now<<1,ll,mid,v),change(now<<1|1,mid+1,rr,v);
Pup(now);
}
unsigned int check(unsigned int now,unsigned int ll,unsigned int rr)
{
if(l[now]==ll&&r[now]==rr) return sum[now];
Pud(now);
unsigned int mid=(l[now]+r[now])>>1;
if(rr<=mid) return check(now<<1,ll,rr);
else if(ll>mid) return check(now<<1|1,ll,rr);
else return check(now<<1,ll,mid)+check(now<<1|1,mid+1,rr);
}
void splay(unsigned int x)
{
unsigned int xx=x;tt=0;
while(!isroot(xx)) tt++,q[tt]=xx,xx=fa[xx];
tt++;q[tt]=xx;
while(tt) pud(q[tt]),tt--;
while(!isroot(x))
{
unsigned int y=fa[x],z=fa[y];
if(!isroot(y))
{
if(ch[z][0]==y^ch[y][0]==x) rotate(x);
else rotate(y);
}
rotate(x);
}
}
void changeit(unsigned int x,unsigned int v)
{
if(x==root) change(1,1,n,v);
else if(sit[root]>=sit[x]&&sit[x]+Siz[x]>=sit[root]+Siz[root])
{
x=GET(x,root);
if(sit[x]>1)
change(1,1,sit[x]-1,v);
if(sit[x]+Siz[x]-1<n)
change(1,sit[x]+Siz[x],n,v);
}
else change(1,sit[x],sit[x]+Siz[x]-1,v);
}
void access(unsigned int x)
{
unsigned int t=0;
while(x)
{
splay(x);
if(ch[x][1]) changeit(L[ch[x][1]],1);
ch[x][1]=t;
if(t) changeit(L[t],-1);
pup(x);
t=x;
x=fa[x];
}
}
void makeroot(unsigned int x)
{
access(x);
splay(x);
swap(ch[x][0],ch[x][1]);
swap(L[x],R[x]);
rev[x]^=1;
}
double checkit(unsigned int x)
{
if(x==root) return (double)1.0*check(1,1,n)/n;
else if(sit[root]>=sit[x]&&sit[x]+Siz[x]>=sit[root]+Siz[root])
{
double tmp=0;
x=GET(x,root);
if(sit[x]>1)
tmp+=check(1,1,sit[x]-1);
if(sit[x]+Siz[x]-1<n)
tmp+=check(1,sit[x]+Siz[x],n);
return (double)tmp/(n-Siz[x]);
}
else return (double)1.0*check(1,sit[x],sit[x]+Siz[x]-1)/Siz[x];
}
int main()
{
scanf("%d%d",&n,&m);
unsigned int i,j,x,y;
for(i=1;i<n;i++)
{
scanf("%d%d",&x,&y);
ae(x,y);ae(y,x);
}
build1(1);
make(1,1);
for(i=1;i<=n;i++)
L[i]=R[i]=i;
build(1,1,n);
char s[21];
unsigned int tot=0,st;
//		st=clock();
while(m--)
{
scanf("%s%d",s,&x);
if(s[2]=='L') access(x);
else if(s[2]=='C')
{
makeroot(x);
root=x;
}
else printf("%.10lf\n",checkit(x)+1.0);
}
}


 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: