1. 程式人生 > >bzoj 3779 重組病毒——LCT維護子樹信息

bzoj 3779 重組病毒——LCT維護子樹信息

發現 lan 然而 spl 之間 sca getch pro str

題目:https://www.lydsy.com/JudgeOnline/problem.php?id=3779

調了很久……已經懶得寫題解了。https://www.cnblogs.com/Zinn/p/10124183.html

線段樹和LCT是分開的。線段樹的子樹一直是相對於 1 號點而言。線段樹上維護的值總是相對於當前的 rt 的。

怎麽保證一直是相對於當前 rt 的呢?發現如果 rt 和 rt‘ 之間的鏈上全是重邊,則每個子樹對於 rt 的答案和對於 rt‘ 的答案是一樣的。

所以在換 rt 的時候先按相對於原 rt 的情況把子樹信息維護好,等到把鏈都弄成重邊之後,值們自然而然就變成相對於新 rt 的了。

寫了區間修改區間查詢的樹狀數組。

註意樹狀數組的 add( ) 裏傳的那個 k 應該是 long long 類型!!!因為有 init( ) ,所以它傳的不是 +1 * (int以內的數) ,還是可能爆 int 的!!!

但為什麽總是對拍不出問題?大概因為自己建的是隨機樹,深度期望 log ;i * d[ i ] 的那個 d[ i ] (差分數組)是對深度的差分,所以總是拍不出錯吧。

#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
#define ls Ls[cr]
#define
rs Rs[cr] using namespace std; const int N=1e5+5,K=20; int n,hd[N],xnt,to[N<<1],nxt[N<<1],rt; int dep[N],fa[N],pre[N][K],c[N][2],dfn[N],siz[N],tot; int sta[N],top; ll tmp[N],f[N],fi[N]; bool rev[N]; int rdn() { int ret=0;bool fx=1;char ch=getchar(); while(ch>9||ch<0){if(ch==
-)fx=0;ch=getchar();} while(ch>=0&&ch<=9)ret=ret*10+ch-0,ch=getchar(); return fx?ret:-ret; } void add(int x,int y){to[++xnt]=y;nxt[xnt]=hd[x];hd[x]=xnt;} void dfs(int cr) { dfn[cr]=++tot;siz[cr]=1; dep[cr]=dep[fa[cr]]+1;tmp[tot]=dep[cr]; pre[cr][0]=fa[cr]; for(int i=1;pre[pre[cr][i-1]][i-1];i++) pre[cr][i]=pre[pre[cr][i-1]][i-1]; for(int i=hd[cr],v;i;i=nxt[i]) if(!dfn[v=to[i]]) { fa[v]=cr;dfs(v); siz[cr]+=siz[v]; } } void add(int x,ll k,ll *f){for(;x<=n;x+=(x&-x))f[x]+=k;}//ll k! for init ll qry(int x,ll *f){ll ret=0;for(;x;x-=(x&-x))ret+=f[x];return ret;} ll qry(int x) { ll ret=0;int yx=x+1; for(;x;x-=(x&-x))ret+=(ll)yx*f[x]-fi[x];return ret; } void init() { for(int i=n;i;i--)tmp[i]-=tmp[i-1],add(i,tmp[i],f); for(int i=1;i<=n;i++)tmp[i]*=i,add(i,tmp[i],fi); } void mdfy(int L,int R,int k) { if(L>R)return;///// add(L,k,f);add(R+1,-k,f); add(L,k*L,fi);add(R+1,-k*(R+1),fi); } ll query(int L,int R) { if(L>R)return 0;/// ll a=(R+1)*qry(R,f)-qry(R,fi); ll b=L*qry(L-1,f)-qry(L-1,fi); return a-b; } bool isroot(int x){return c[fa[x]][0]!=x&&c[fa[x]][1]!=x;} void Rev(int x) { if(!rev[x])return;rev[x]=0; rev[c[x][0]]^=1;rev[c[x][1]]^=1; swap(c[x][0],c[x][1]); } void rotate(int x) { int y=fa[x],z=fa[y],d=(x==c[y][1]); if(!isroot(y))c[z][y==c[z][1]]=x; fa[x]=z; fa[c[x][!d]]=y;fa[y]=x; c[y][d]=c[x][!d];c[x][!d]=y; } void splay(int x) { sta[top=1]=x; for(int k=x;!isroot(k);k=fa[k])sta[++top]=fa[k]; for(int i=top;i;i--)Rev(sta[i]); int y,z; while(!isroot(x)) { y=fa[x];z=fa[y]; if(!isroot(y)) ((x==c[y][1])^(y==c[z][1]))?rotate(x):rotate(y); rotate(x); } } int fnd(int x) {Rev(x);while(c[x][0])x=c[x][0],Rev(x);return x;} int fnd(int x,int f) { for(int i=17;i>=0;i--) if(dep[pre[x][i]]>dep[f])x=pre[x][i]; return x; } bool intree(int x,int rt) {return dfn[x]>=dfn[rt]&&dfn[x]<dfn[rt]+siz[rt];} void chg(int x,int k) { if(!intree(rt,x))mdfy(dfn[x],dfn[x]+siz[x]-1,k); else { int d=fnd(rt,x);//d!! mdfy(1,dfn[d]-1,k);mdfy(dfn[d]+siz[d],n,k); } } void access(int x) { int t=0; while(x) { splay(x); if(c[x][1])chg(fnd(c[x][1]),1); if(t)chg(fnd(t),-1); c[x][1]=t; t=x;x=fa[x]; } } void makeroot(int x) { access(x);splay(x);rev[x]^=1;rt=x;//rt=x after access(x) } double query(int x) { if(x==rt) return (double)query(1,n)/n; if(intree(rt,x)) { int d=fnd(rt,x); ll ret=query(1,dfn[d]-1)+query(dfn[d]+siz[d],n); return (double)ret/(n-siz[d]); } return (double)query(dfn[x],dfn[x]+siz[x]-1)/siz[x]; } int main() { n=rdn();int Q=rdn(); for(int i=1,u,v;i<n;i++) { u=rdn();v=rdn();add(u,v);add(v,u); } dfs(1);init(); char ch[10];int x;rt=1; while(Q--) { scanf("%s",ch);x=rdn(); if(ch[2]==L)access(x); if(ch[2]==C)makeroot(x); if(ch[2]==Q)printf("%.10f\n",query(x)); } return 0; }

bzoj 3779 重組病毒——LCT維護子樹信息