BZOJ 3091 城市旅行 (LCT)

题目大意:

 

很显然是一个$LCT$题= =

操作1,2都是$LCT$基本操作,操作3打个标记即可

重点就是操作4该如何在$LCT$里维护,我们先不管期望的问题,只需要把总和$/(sum*(sum+1)/2)$即可

我们把链拎出来,摊平

每个节点的答案,就是它(左侧节点数+1)*(右侧节点数+1)*它的权值

我们在用$splay$维护动态链时,$splay$树中,我们每个节点为根的子树都能表示一条链

一个节点$x$连接了左右子节点$ls,rs$,那么,$x$子树表示的链,相当于把$ls$的链,$x$节点,$rs$的链的接在了一起

我们需要把它们的信息进行合并

发现这其实是一个卷积的形式

$splay$中,每个节点维护,子树中节点数量$sz$,子树中节点权值总和$sum$,以及$lx,rx$表示它子树中所有节点的权值*(这些节点左/右侧节点数量+1),最后一个答案数组$tx$

这几个数组在$pushup$里很好处理,建议自己推式子

关键是在$update$后,下推标记时该如何处理。我们必须保证下推标记后,子节点的$lx,rx,tx$数组能$O(1)$更新

设增加的权值是$tag$

显然$lx,rx$都会增加$tag*sz_{x}*(sz_{x}+1)/2$,把链摊开,$tag$对每个节点的贡献是一个等差数列

$tag$对答案$tx$的更新值是$\sum i\cdot(sz-i+1)$ 其中$i$表示它在摊开链中的位置

展开,再用$1~n$平方和公式,可得$tag$对答案的贡献是$tag*sz*(sz+1)*(sz+2)/6$

注意!$revers$操作需要把$lx$和$rx$交换!

另外由于操作中可能有一部分边不能连,每次都$findroot$会消耗大量时间

所以每次$findroot$后,把根转上去能大幅优化常数

还有,$namespace$跑得是真的慢..$struct$就飞快

  1 #include <queue>
  2 #include <vector>
  3 #include <cstdio>
  4 #include <cstring>
  5 #include <algorithm>
  6 #define N1 50100
  7 #define M1 2010
  8 #define S1 (N1<<1)
  9 #define T1 (N1<<2)
 10 #define ll long long
 11 #define uint unsigned int
 12 #define rint register int 
 13 #define ull unsigned long long
 14 #define dd double
 15 #define il inline 
 16 #define inf 1000000000
 17 using namespace std;
 18 
 19 int gint()
 20 {
 21     int ret=0,fh=1;char c=getchar();
 22     while(c<'0'||c>'9'){if(c=='-')fh=-1;c=getchar();}
 23     while(c>='0'&&c<='9'){ret=ret*10+c-'0';c=getchar();}
 24     return ret*fh;
 25 }
 26 int n,m,T,type;
 27 int tot;
 28 struct LCT{
 29 int ch[N1][2],fa[N1],rev[N1],val[N1],tag[N1];
 30 ll lx[N1],rx[N1],tx[N1],sum[N1],sz[N1];
 31 inline int idf(int x){return ch[fa[x]][0]==x?0:1;}
 32 inline int isroot(int x){return (ch[fa[x]][0]==x||ch[fa[x]][1]==x)?0:1;}
 33 void revers(int x)
 34 {
 35     swap(ch[x][0],ch[x][1]);
 36     swap(lx[ch[x][0]],rx[ch[x][0]]);
 37     swap(lx[ch[x][1]],rx[ch[x][1]]);
 38     rev[x]^=1;
 39 }
 40 void pushup(int x)
 41 {
 42     int ls=ch[x][0],rs=ch[x][1];
 43     sz[x]=sz[ls]+sz[rs]+1;
 44     sum[x]=sum[ls]+sum[rs]+val[x];
 45     lx[x]=lx[ls]+lx[rs]+1ll*(sum[ls]+val[x])*(sz[rs]+1);
 46     rx[x]=rx[ls]+rx[rs]+1ll*(sum[rs]+val[x])*(sz[ls]+1);
 47     tx[x]=tx[ls]+tx[rs]+1ll*rx[ls]*(sz[rs]+1)+1ll*lx[rs]*(sz[ls]+1)+1ll*val[x]*(sz[ls]+1)*(sz[rs]+1);
 48 }
 49 void pushdown(int x)
 50 {
 51     if(rev[x])
 52     {
 53         if(ch[x][0]) revers(ch[x][0]);
 54         if(ch[x][1]) revers(ch[x][1]);
 55         rev[x]^=1;
 56     }
 57     if(tag[x])
 58     {
 59         int ls=ch[x][0],rs=ch[x][1]; ll w=tag[x];
 60         if(ls)
 61         {
 62             tag[ls]+=w,val[ls]+=w,sum[ls]+=1ll*sz[ls]*w;
 63             lx[ls]+=1ll*w*(sz[ls]+1)*sz[ls]/2;
 64             rx[ls]+=1ll*w*(sz[ls]+1)*sz[ls]/2;
 65             tx[ls]+=1ll*sz[ls]*(sz[ls]+1)*(sz[ls]+2)/6*w;
 66         }
 67         if(rs)
 68         {
 69             tag[rs]+=w,val[rs]+=w,sum[rs]+=1ll*sz[rs]*w;
 70             lx[rs]+=1ll*(sz[rs]+1)*sz[rs]/2*w;
 71             rx[rs]+=1ll*(sz[rs]+1)*sz[rs]/2*w;
 72             tx[rs]+=1ll*sz[rs]*(sz[rs]+1)*(sz[rs]+2)/6*w;
 73         }
 74         tag[x]=0;
 75     }
 76 }
 77 void rot(int x)
 78 {
 79     int y=fa[x],ff=fa[y],px=idf(x),py=idf(y);
 80     if(!isroot(y)) ch[ff][py]=x; fa[x]=ff;
 81     fa[ch[x][px^1]]=y,ch[y][px]=ch[x][px^1];
 82     ch[x][px^1]=y,fa[y]=x;
 83     pushup(y),pushup(x);
 84 }
 85 int stk[N1],tp;
 86 void splay(int x)
 87 {
 88     int y=x; stk[++tp]=x;
 89     while(!isroot(y)){stk[++tp]=fa[y],y=fa[y];}
 90     while(tp){pushdown(stk[tp--]);}
 91     while(!isroot(x))
 92     {
 93         y=fa[x];
 94         if(isroot(y)) rot(x);
 95         else if(idf(y)==idf(x)) rot(y),rot(x);
 96         else rot(x),rot(x);
 97     }
 98 }
 99 void access(int x)
100 {
101     for(int y=0;x;y=x,x=fa[x]) 
102         splay(x),ch[x][1]=y,pushup(x);
103 }
104 void mkroot(int x)
105 {
106     access(x),splay(x),revers(x);
107     swap(lx[x],rx[x]);
108 }
109 int fdroot(int x)
110 {
111     access(x),splay(x); 
112     while(ch[x][0]) x=ch[x][0],pushdown(x);
113     splay(x); return x;
114 }
115 void split(int x,int y){mkroot(x),access(y),splay(y);}
116 void link(int x,int y)
117 {
118     mkroot(x);
119     if(fdroot(y)!=x) fa[x]=y;
120 }
121 void cut(int x,int y)
122 {
123     split(x,y);
124     if(!ch[x][1]&&fa[x]==y&&ch[y][0]==x) 
125         ch[y][0]=fa[x]=0,pushup(y);
126 }
127 ll query(int x,int y)
128 {
129     split(x,y);
130     if(fdroot(y)!=x) return -1; 
131     return tx[x];
132 }
133 void update(int x,int y,int w)
134 {
135     split(x,y);
136     if(fdroot(y)!=x) return;
137     tag[x]+=w,val[x]+=w,sum[x]+=1ll*w*sz[x];
138     lx[x]+=1ll*w*(sz[x]+1)*sz[x]/2;
139     rx[x]+=1ll*w*(sz[x]+1)*sz[x]/2;
140     tx[x]+=1ll*sz[x]*(sz[x]+1)*(sz[x]+2)/6*w;
141 }
142 void init(){for(int i=1;i<=n;i++) sz[i]=1,pushup(i);}
143 }lct;
144 ll gcd(ll x,ll y){if(!y) return x; return gcd(y,x%y);}
145 
146 int main()
147 {
148     int i,j,x,y,w,fl;ll ans,g,nn;
149     scanf("%d%d",&n,&m);
150     for(i=1;i<=n;i++) lct.val[i]=gint();
151     lct.init();
152     for(j=1;j<n;j++) x=gint(), y=gint(), lct.link(x,y);
153     for(j=1;j<=m;j++)    
154     {
155         fl=gint(); x=gint(); y=gint();
156         if(fl==1) lct.cut(x,y);
157         if(fl==2) lct.link(x,y);
158         if(fl==3) w=gint(),lct.update(x,y,w);
159         if(fl==4)
160         {
161             ans=lct.query(x,y);
162             if(ans==-1) {puts("-1");continue;}
163             nn=1ll*(lct.sz[x])*(lct.sz[x]+1)/2;
164             g=gcd(ans,nn);
165             printf("%lld/%lld\n",ans/g,nn/g);
166         }
167     }
168     return 0;
169 }

 

posted @ 2018-12-24 17:03  guapisolo  阅读(203)  评论(0编辑  收藏  举报