P3178 - 树上操作
作者:互联网
没什么特殊的一道树链剖分板子题,可以作为树剖入门题
操作1单点修改即可
操作2和操作3为树链剖分基础操作
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> #include<queue> using namespace std; #define lid (id << 1) #define rid (id << 1) | 1 typedef long long LL; const int maxn=1e5+10; struct Edge{ int nex; int to; }E[2*maxn]; LL rt,n,m,r,cnt,tot; LL mod=9223372036854775806; LL a[2*maxn]; LL head[maxn]; LL f[maxn];//节点u的父亲节点 LL d[maxn];//节点u的深度 LL size[maxn];//以u为根的子树节点个数 LL son[maxn];//重儿子 LL rk[maxn];//当前dfs标号在树中所对应的节点 LL top[maxn];//当前节点所在链的顶端节点 LL id[maxn];//树中每个节点剖分以后的新编号(决定DFS执行顺序) struct seg_tree { LL l, r; LL lazy; long long sum; } tree[maxn << 2]; void build(LL id, LL l, LL r) { tree[id].l = l; tree[id].r = r; if (l == r) { tree[id].sum = a[rk[l]]; return; } int mid = (l + r) >> 1; build(lid, l, mid); build(rid, mid + 1, r); tree[id].sum = (tree[lid].sum + tree[rid].sum)%mod; } void pushdown(LL id) { if (tree[id].lazy != 0 && tree[id].l != tree[id].r) { LL val = tree[id].lazy; (tree[lid].lazy += val)%=mod; (tree[rid].lazy += val)%=mod; tree[lid].sum += val * (tree[lid].r - tree[lid].l + 1); tree[rid].sum += val * (tree[rid].r - tree[rid].l + 1); tree[id].lazy = 0; } } void add(LL id, LL val,LL l, LL r) { pushdown(id); if (tree[id].l == l && tree[id].r == r) { tree[id].lazy += val; tree[id].sum += val * (r - l + 1); tree[id].sum%=mod; return; } LL mid = (tree[id].l + tree[id].r) >> 1; if (mid >= r) add(lid, val, l, r); else if (mid < l) add(rid, val, l, r); else { add(lid, val, l, mid); add(rid, val, mid + 1, r); } tree[id].sum = (tree[lid].sum + tree[rid].sum)%mod; } long long query(LL id,LL l, LL r) { pushdown(id); if (tree[id].l == l && tree[id].r == r) return tree[id].sum; LL mid = (tree[id].l + tree[id].r) >> 1; if (mid >= r) return query(lid, l, r)%mod; else if (mid < l) return query(rid, l, r)%mod; else return (query(lid, l, mid) + query(rid, mid + 1, r))%mod; } void addedge(int u,int v) { E[++tot].nex=head[u]; E[tot].to=v; head[u]=tot; } void dfs1(int u,int fa,int depth) { f[u]=fa; d[u]=depth; size[u]=1; for(int i=head[u];i;i=E[i].nex) { int v=E[i].to; if(v==fa)continue; dfs1(v,u,depth+1); size[u]+=size[v]; if(size[v]>size[son[u]]) { son[u]=v; }//选取重儿子 } } void dfs2(int u,int t)//t为重链顶端,连接重链,记录dfs,处理top,id,rk以保证dfs序连续 { top[u]=t; id[u]=++cnt;//记录dfs序 rk[cnt]=u;//记录相应dfs序的节点 if(!son[u]) { return; } dfs2(son[u],t); for(int i=head[u];i;i=E[i].nex) { int v=E[i].to; if(v!=son[u]&&v!=f[u]) dfs2(v,v); //轻链底端结点即为重链的顶端 } } LL sum(int x,int y) { LL ans=0; int fx=top[x]; int fy=top[y]; while(top[x]!=top[y]) { if(d[top[x]]<d[top[y]])swap(x,y); (ans+=query(1,id[top[x]],id[x]))%=mod; x=f[top[x]]; } if(id[x]>id[y])swap(x,y); (ans+=query(1,id[x],id[y]))%=mod; return ans; } void update(int x,int y,int c) { while(top[x]!=top[y]) { if(d[top[x]]<d[top[y]]) { swap(x,y); } add(1,c,id[top[x]],id[x]); x=f[top[x]]; } if(id[x]>id[y])swap(x,y); add(1,c,id[x],id[y]); } int main(){ scanf("%lld%lld",&n,&m); r=1; for(int i=1;i<=n;i++) { scanf("%lld",&a[i]); } for(int i=1;i<n;i++) { int x,y; scanf("%d%d",&x,&y); addedge(x,y); addedge(y,x); } dfs1(r,0,1); dfs2(r,r); rt=1; build(1,1,n); for(int i=1;i<=m;i++) { LL flag,x,y,z; scanf("%lld",&flag); if(flag==1) { scanf("%lld%lld",&x,&z); add(1,z,id[x],id[x]); } if(flag==3){ scanf("%lld",&x); printf("%lld\n",sum(x,1)); } if(flag==2) { scanf("%lld%lld",&x,&y); add(1,y,id[x],id[x]+size[x]-1); } } return 0; //处理深度d以及父节点f }
标签:P3178,val,int,LL,tree,mid,操作,树上,id 来源: https://www.cnblogs.com/lemonGJacky/p/15305230.html