欢迎访问~原文出处——博客园-zhouzhendong
去博客园看该题解
题目传送门 - BZOJ2631
题意概括
一棵n个节点的树,每一个节点有一个权值,m次操作。
要支持操作有:删边、连边、区间求和、区间加、区间乘。
保证操作过程中不出现环。
n,m<=100000
题解
差不多是基础的LCT,加个懒标记。
2个懒标记,一个是乘的,一个是加的,下传的时候先乘后加。
注意用无符号的int,用LL会超时。
(数据较为友善,不卡无符号int)
代码
#include <cstring> #include <cstdio> #include <cstdlib> #include <algorithm> #include <cmath> using namespace std; typedef long long LL; typedef unsigned int U; const int N=100005; const U Mod=51061; int n,m; int fa[N],son[N][2],rev[N]; U sum[N],addt[N],addp[N],val[N],size[N]; bool isd(char ch){ return '0'<=ch&&ch<='9'; } void read(int &x){ char ch=getchar(); x=0; while (!isd(ch)) ch=getchar(); while (isd(ch)) x=x*10+ch-48,ch=getchar(); } bool isroot(int x){ return son[fa[x]][0]!=x&&son[fa[x]][1]!=x; } void pushup(int x){ if (!x) return; sum[x]=(sum[son[x][0]]+sum[son[x][1]]+val[x])%Mod; size[x]=(size[son[x][0]]+size[son[x][1]]+1)%Mod; } void pushson(int x,U t,U p){ if (!x) return; addt[x]=addt[x]*t%Mod; addp[x]=(addp[x]*t+p)%Mod; val[x]=(val[x]*t+p)%Mod; sum[x]=(sum[x]*t+p*size[x])%Mod; } void pushdown(int x){ if (!x) return; int &ls=son[x][0],&rs=son[x][1]; if (rev[x]){ rev[x]=0; rev[ls]^=1; rev[rs]^=1; swap(ls,rs); } U &t=addt[x],&p=addp[x]; pushson(ls,t,p); pushson(rs,t,p); t=1,p=0; } void pushadd(int x){ if (!x) return; if (!isroot(x)) pushadd(fa[x]); pushdown(x); } int wson(int x){ return son[fa[x]][1]==x; } void rotate(int x){ if (isroot(x)) return; int y=fa[x],z=fa[y],L=wson(x),R=L^1; if (!isroot(y)) son[z][wson(y)]=x; fa[x]=z,fa[y]=x,fa[son[x][R]]=y; son[y][L]=son[x][R],son[x][R]=y; pushup(y); pushup(x); } void splay(int x){ pushadd(x); for (int y=fa[x];!isroot(x);rotate(x),y=fa[x]) if (!isroot(y)) rotate(wson(x)==wson(y)?y:x); } void access(int x){ int t=0; while (x){ splay(x); son[x][1]=t; pushup(x); t=x; x=fa[x]; } } void rever(int x){ access(x); splay(x); rev[x]^=1; } void link(int x,int y){ rever(x); fa[x]=y; } void cut(int x,int y){ rever(x); access(y); splay(y); fa[x]=son[y][0]=0; } int main(){ read(n),read(m); for (int i=1;i<=n;i++){ val[i]=sum[i]=size[i]=addt[i]=1; fa[i]=son[i][0]=son[i][1]=addp[i]=rev[i]=0; } for (int i=1,a,b;i<n;i++){ read(a),read(b); link(a,b); } while (m--){ char op[4]; int a,b,c,d; scanf("%s",op); if (op[0]=='+'){ read(a),read(b),read(c); rever(a); access(b); splay(b); pushson(b,1,c); } if (op[0]=='-'){ read(a),read(b),read(c),read(d); cut(a,b); link(c,d); } if (op[0]=='*'){ read(a),read(b),read(c); rever(a); access(b); splay(b); pushson(b,c,0); } if (op[0]=='/'){ read(a),read(b); rever(a); access(b); splay(b); printf("%u ",sum[b]); } } return 0; }