题解 P3384 【【模板】树链剖分】

teafrogsf

2017-10-11 21:22:04

Solution

本题是树链剖分的裸题。虽然大家都知道,树状数组的常数比较小,但由于太难写了,于是大部分人也都是写的线段树。 我的代码163行,而这个行数是**纯天然缩行**形成的,也就是说通过人工压缩可以压到150行以内。 而且这个代码实际上还是长了。为什么呢?因为我用了许多if来取模。 不开long long的原因是在Linux下long long会变得特别慢,而线段树常数也比较大。 而如果有时候不分青红皂白直接取模就会导致有时候会变得比较慢,某些题目会故意这样来卡常数。 此外注意**等于**mod数也要取模。 实测比我的同学快300ms。 主要是讲述以上的优化思路,代码仅供参考,每个人的代码风格都不一样,重要的是细心。 ```cpp #include<cstdio> #include<iostream> #define neko 100010 #define meko 100010 #define mid ((l+r)>>1) #define lson root<<1,l,mid #define rson root<<1|1,mid+1,r #define ori tagl,tagr #define f(i,a,b) for(register int i=a;i<=b;++i) using std::swap; int Sum[neko<<2],Add[neko<<2]; typedef int arr[neko]; int n,m,root,mod,t,cnt; arr siz,fa,son,top,dep,w,head,ord,a; //first dfs: siz fa son dep //second dfs: top struct node { int u,v,next; }e[meko<<1]; void read(int &x) { char c=getchar();int p=1;x=0; while(!isdigit(c)){c=getchar();if(c=='-')p=-1;} while(isdigit(c)) { x=(x<<1)+(x<<3)+(c^'0'); c=getchar(); }x*=p; } void add(int x,int y) { e[++t].u=x; e[t].v=y; e[t].next=head[x]; head[x]=t; } void dfs(int u)//其实这是树剖最容易打的地方 { dep[u]=dep[fa[u]]+1; siz[u]=1; for(int i=head[u];i;i=e[i].next) { int v=e[i].v; if(v!=fa[u]) { fa[v]=u; dfs(v); siz[u]+=siz[v]; if(son[u]==-1||siz[v]>siz[son[u]])son[u]=v; } } } void dfs2(int u) { w[u]=++cnt; ord[cnt]=u; if(u==son[fa[u]])top[u]=top[fa[u]]; else top[u]=u; if(son[u]!=-1)dfs2(son[u]); for(int i=head[u];i;i=e[i].next) { int v=e[i].v; if(v!=fa[u]&&v!=son[u])dfs2(v); } } void pushup(int root) { Sum[root]=Sum[root<<1]+Sum[root<<1|1]; if(Sum[root]>=mod)Sum[root]%=mod; } void build(int root,int l,int r) { if(l==r)Sum[root]=a[ord[l]]; else { build(lson); build(rson); pushup(root); } } void pushdown(int root,int l,int r) { if(Add[root]) { Add[root<<1]+=Add[root]; Add[root<<1|1]+=Add[root]; if(Add[root<<1]>=mod)Add[root<<1]%=mod; if(Add[root<<1|1]>=mod)Add[root<<1|1]%=mod; Sum[root<<1]+=(mid-l+1)*Add[root]; Sum[root<<1|1]+=(r-mid)*Add[root]; if(Sum[root<<1]>=mod)Sum[root<<1]%=mod; if(Sum[root<<1|1]>=mod)Sum[root<<1|1]%=mod; Add[root]=0; } } void update(int root,int l,int r,int tagl,int tagr,int x) { if(l>=tagl&&r<=tagr) { Add[root]+=x; Sum[root]+=(r-l+1)*x; if(Sum[root]>=mod)Sum[root]%=mod; } else { pushdown(root,l,r); if(tagl<=mid)update(lson,ori,x); if(tagr>mid)update(rson,ori,x); pushup(root); } } int query(int root,int l,int r,int tagl,int tagr) { if(l>=tagl&&r<=tagr)return Sum[root]; else { pushdown(root,l,r); int tmp=0; if(tagl<=mid)tmp+=query(lson,ori); if(tmp>=mod)tmp%=mod; if(tagr>mid)tmp+=query(rson,ori); return tmp>=mod?tmp%mod:tmp; } } void pathu(int l,int r,int x) { while(top[l]!=top[r]) { if(dep[top[l]]<dep[top[r]])swap(l,r); update(1,1,n,w[top[l]],w[l],x); l=fa[top[l]]; }if(dep[l]>dep[r])swap(l,r); update(1,1,n,w[l],w[r],x); } int pathq(int l,int r) { int sum=0; while(top[l]!=top[r]) { if(dep[top[l]]<dep[top[r]])swap(l,r); sum+=query(1,1,n,w[top[l]],w[l]);if(sum>=mod)sum%=mod; l=fa[top[l]]; }if(dep[l]>dep[r])swap(l,r); return (sum+query(1,1,n,w[l],w[r]))%mod; } int main() { int _,_2,_3,_4,x,y; read(n),read(m),read(root),read(mod); f(i,1,n)read(a[i]),son[i]=-1; f(i,1,n-1)read(x),read(y),add(x,y),add(y,x); dfs(root); dfs2(root); build(1,1,n); f(i,1,m) { read(_),read(_2); if(_==1)read(_3),read(_4),pathu(_2,_3,_4); if(_==2)read(_3),printf("%d\n",pathq(_2,_3)); if(_==3)read(_3),update(1,1,n,w[_2],w[_2]+siz[_2]-1,_3); if(_==4)printf("%d\n",query(1,1,n,w[_2],w[_2]+siz[_2]-1)); }return 0; } ```