bzoj 3779: 重组病毒【LCT+线段树维护dfs序】
2018-01-08 20:46
344 查看
%.8lf会WA!!%.8lf会WA!!%.8lf会WA!!要%.10lf!!
和4817有点像,但是更复杂。
首先对于操作一“在编号为x的计算机中植入病毒的一个新变种,在植入一个新变种时,病毒会在局域网中搜索核心计算机的位置,并沿着网络中最短的路径感染过去”,长得是不是有点像LCT中的access操作?进而发现,如果把同一颜色的点连起来作为LCT中的重边的话,那么询问二就相当于问路径上的虚边有多少。
假设没有换根操作,那么第二、三个操作是可以用树剖在线段树上维护的。 设每个点的权值val为这个点到根的路径上颜色个数,也就是虚边个数。那么考虑access操作的影响,对于他断开的重边,所在子树加一,对于他连上的重边,所在子树减一。直接在access过程中处理即可。
那么现在考虑换根操作:
首先出题人非常贴心的在换根操作后加了一个access,更加符合LCT的操作方式虽然不加应该就做不了了
首先对1为根进行dfs,把dfs序摊到线段树上,在这个线段树上维护修改和查询。
然后把平均数改成区间和,查完之后直接除即可(注意会爆int,注意精度问题)。
那么对于当先换根换到的root和要查询的子树x,用dfs序判断有三种情况:
- \( root=x \),相当于求全区间和,直接返回即可;
- x在root的子树中,那么换根对它没有影响,直接当做没有换根来查询即可;
- x不在root的子树中,那么答案为全区间和减去x下面root所在的子树的区间和。
#include<iostream> #include<cstdio> using namespace std; const int N=300005; int n,m,h ,cnt,fa ,de ,fr ,ed ,id ,dfn,rl ,root=1,s ,top; char c[10]; struct qwe { int ne,to; }e[N<<1]; struct xianduanshu { int l,r; long long sum,lz; }q[N<<2]; struct pinghengshu { int f,c[2],tg; }t ; int read() { int r=0,f=1; char p=getchar(); while(p>'9'||p<'0') { if(p==-1) f=-1; p=getchar(); } while(p>='0'&&p<='9') { r=r*10+p-48; p=getchar(); } return r*f; } void add(int u,int v) { cnt++; e[cnt].ne=h[u]; e[cnt].to=v; h[u]=cnt; } void build(int ro,int l,int r) { q[ro].l=l,q[ro].r=r; if(l==r) return; int mid=(l+r)>>1; build(ro<<1,l,mid); build(ro<<1|1,mid+1,r); } void pd(int ro) { q[ro<<1].sum+=q[ro].lz*(q[ro<<1].r-q[ro<<1].l+1); q[ro<<1].lz+=q[ro].lz; q[ro<<1|1].sum+=q[ro].lz*(q[ro<<1|1].r-q[ro<<1|1].l+1); q[ro<<1|1].lz+=q[ro].lz; q[ro].lz=0; } void update(int ro,int l,int r,int v) {//cout<<l<<" "<<r<<" "<<v<<endl; if(l>r) return; if(q[ro].l==l&&q[ro].r==r) { q[ro].sum+=v*(q[ro].r-q[ro].l+1); q[ro].lz+=v; return; } if(q[ro].lz) pd(ro); int mid=(q[ro].l+q[ro].r)>>1; if(r<=mid) update(ro<<1,l,r,v); else if(l>mid) update(ro<<1|1,l,r,v); else { update(ro<<1,l,mid,v); update(ro<<1|1,mid+1,r,v); } q[ro].sum=q[ro<<1].sum+q[ro<<1|1].sum; } long long ques(int ro,int l,int r) { if(l>r) return 0; if(q[ro].l==l&&q[ro].r==r) return q[ro].sum; if(q[ro].lz) pd(ro); int mid=(q[ro].l+q[ro].r)>>1; if(r<=mid) return ques(ro<<1,l,r); else if(l>mid) return ques(ro<<1|1,l,r); else return ques(ro<<1,l,mid)+ques(ro<<1|1,mid+1,r); } void dfs(int u,int fat) { t[u].f=fa[u]=fat; de[u]=de[fat]+1; fr[u]=++dfn; update(1,fr[u],fr[u],de[u]); for(int i=h[u];i;i=e[i].ne) if(e[i].to!=fat) dfs(e[i].to,u); ed[u]=dfn; } bool srt(int x) { return t[t[x].f].c[0]!=x&&t[t[x].f].c[1]!=x; } void pud(int x) { if(t[x].tg) { t[x].tg=0; t[t[x].c[0]].tg^=1; t[t[x].c[1]].tg^=1; swap(t[x].c[0],t[x].c[1]); } } void zhuan(int x) { int l,r,y=t[x].f,z=t[y].f; if(t[y].c[0]==x) l=0; else l=1; r=l^1; if(!srt(y)) { if(t[z].c[0]==y) t[z].c[0]=x; else t[z].c[1]=x; } t[x].f=z;t[y].f=x; t[t[x].c[r]].f=y; t[y].c[l]=t[x].c[r]; t[x].c[r]=y; } void splay(int x) {//cout<<"splay"<<x<<endl; top=0; s[++top]=x; for(int i=x;!srt(i);i=t[i].f) s[++top]=t[i].f; while(top) pud(s[top--]); while(!srt(x)) { int y=t[x].f,z=t[y].f; if(!srt(y)) { if((t[y].c[0]==x)^(t[z].c[0]==y)) zhuan(x); else zhuan(y); } zhuan(x); } } int zhao(int x,int y) { for(int i=h[x];i;i=e[i].ne) if(e[i].to!=fa[x]&&fr[y]>=fr[e[i].to]&&ed[y]<=ed[e[i].to]) return e[i].to; return 0; } void jia(int x,int w) { if(x==root) update(1,1,n,w); else if(fr[root]>=fr[x]&&ed[root]<=ed[x]) { int zi=zhao(x,root); update(1,1,fr[zi]-1,w); update(1,ed[zi]+1,n,w); } else update(1,fr[x],ed[x],w); } int wk(int x) { pud(x); while(t[x].c[0]) x=t[x].c[0],pud(x); return x; } void acc(int x) { for(int i=0;x;i=x,x=t[x].f) { splay(x); if(t[x].c[1]) jia(wk(t[x].c[1]),1); t[x].c[1]=i; if(t[x].c[1]) jia(wk(t[x].c[1]),-1); } } void mkrt(int x) { acc(x); splay(x); root=x; t[x].tg^=1; } double wen(int x) {//cout<<ques(1,id[x],id[x]+si[x]-1)<<endl; if(x==root) return (double)ques(1,1,n)/n; if(fr[root]>=fr[x]&&ed[root]<=ed[x]) { int zi=zhao(x,root); return (double)(ques(1,1,fr[zi]-1)+ques(1,ed[zi]+1,n))/(n-(ed[zi]-fr[zi]+1)); } return (double)ques(1,fr[x],ed[x])/(ed[x]-fr[x]+1); } int main() { n=read(),m=read(); for(int i=1;i<n;i++) { int x=read(),y=read(); add(x,y);add(y,x); } build(1,1,n); dfs(1,0); for(int i=2;i<=n;i++) t[i].f=fa[i]; while(m--) { scanf("%s",c); if(c[2]=='L') { int x=read(); acc(x); } else if(c[2]=='C') { int x=read(); mkrt(x); } else { int x=read(); printf("%.10lf\n",wen(x)); } } return 0; }
相关文章推荐
- BZOJ 3779 重组病毒 LCT+线段树维护DFS序
- [LCT 线段树 dfs序] BZOJ 3779 重组病毒
- 【BZOJ3779】重组病毒 LCT+DFS序
- BZOJ 3779 重组病毒 LCT维护子树信息
- bzoj 3779: 重组病毒
- BZOJ3779 重组病毒
- 【BZOJ】3779 重组病毒
- Bzoj3779 重组病毒
- 【bzoj 3779】重组病毒
- bzoj 3779 重组病毒 好题 LCT+dfn序+线段树分类讨论
- bzoj 3779: 重组病毒 LCT+线段树+倍增
- 【bzoj3779】重组病毒 LCT+树上倍增+DFS序+树状数组区间修改区间查询
- bzoj3779-重组病毒
- bzoj3779: 重组病毒
- bzoj3779 重组病毒 [lct+树链剖分]
- 【BZOJ-3779】重组病毒 LinkCutTree + 线段树 + DFS序
- BZOJ3779: 重组病毒
- BZOJ 3779 重组病毒 ——LCT 线段树
- [bzoj] 3779 重组病毒
- bzoj3779 重组病毒