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 遥远的国度”就知道啦,只需要分类讨论一下就好了,当前的子树最多在原来的序列中被切成两段,不影响时间复杂度的!
具体可以看代码:
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); } }
相关文章推荐
- 【算法笔记】贪心算法——01背包问题
- TI CC2541 OAD流程
- 用两个栈组成队列
- Shader Forge 颜色乘法+加法+控制饱和度+角色发光+和程序的衔接
- 同程面试经历 android开发工程师
- 计算机中的布尔操作 ^ (即XOR)的学习
- ActiveMQ编程实例
- 牧羊曲
- Digit(湘潭大学比赛)
- spring+mybatis+ehcahce实现注解缓存
- 线性表的顺序存储结构
- Digit(湘潭大学比赛)
- Hibernate 中的session 的flush、reflush 和clear 方法 ,及数据库的隔离级别
- CentOS7 根目录扩容
- Finereport与Java Web
- OSI七层模型
- Unix & Linux笔记(11)
- python入门神图
- [Sql2008错误问题]附件数据库时出现的3种常见错误的解决办法
- 二进制(2):浮点数