题目描述
如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作:
操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节点的值都加上z
操作2: 格式: 2 x y 表示求树从x到y结点最短路径上所有节点的值之和
操作3: 格式: 3 x z 表示将以x为根节点的子树内所有节点值都加上z
操作4: 格式: 4 x 表示求以x为根节点的子树内所有节点值之和
输入输出格式
输入格式:
第一行包含4个正整数N、M、R、P,分别表示树的结点个数、操作个数、根节点序号和取模数(即所有的输出结果均对此取模)。
接下来一行包含N个非负整数,分别依次表示各个节点上初始的数值。
接下来N-1行每行包含两个整数x、y,表示点x和点y之间连有一条边(保证无环且连通)
接下来M行每行包含若干个正整数,每行表示一个操作,格式如下:
操作1: 1 x y z
操作2: 2 x y
操作3: 3 x z
操作4: 4 x
输出格式:
输出包含若干行,分别依次表示每个操作2或操作4所得的结果(对P取模)
输入输出样例
5 5 2 24 7 3 7 8 0 1 2 1 5 3 1 4 1 3 4 2 3 2 2 4 5 1 5 1 3 2 1 3
2 21
说明
时空限制:1s,128M
数据规模:
对于30%的数据: N \leq 10, M \leq 10N≤10,M≤10
对于70%的数据: N \leq {10}^3, M \leq {10}^3N≤103,M≤103
对于100%的数据: N \leq {10}^5, M \leq {10}^5N≤105,M≤105
( 其实,纯随机生成的树LCA+暴力是能过的,可是,你觉得可能是纯随机的么233 )
样例说明:
树的结构如下:
各个操作如下:
故输出应依次为2、21(重要的事情说三遍:记得取模)
用来练习线段树维护树链剖分的很好的模板题,要注意取模十分的慢,模的太暴力会TLE的。
#include<cstdio> #include<algorithm> #include<cstring> #define LL long long using namespace std; const int maxn=1e5+100; struct edge{ int v,next; }e[maxn*2]; int cnt,idcnt; int top[maxn],fa[maxn],nodew[maxn],d[maxn],tid[maxn],tidend[maxn],nrank[maxn],head[maxn],son[maxn],nbel[maxn]; LL n,m,mod,root; void adde(int u,int v){ e[cnt].v=v; e[cnt].next=head[u]; head[u]=cnt++; } void dfs1(int u,int p){ d[u]=d[p]+1; fa[u]=p; nbel[u]=1; for(int i=head[u];i!=-1;i=e[i].next){ int v=e[i].v; if(v==p) continue; dfs1(v,u); nbel[u]+=nbel[v]; if(son[u]==-1 || nbel[v] > nbel[son[u]]){ son[u]=v; } } } void dfs2(int u,int tp){ tid[u]=++idcnt; nrank[idcnt]=u; top[u]=tp; if(son[u]==-1){ tidend[u]=idcnt; return; } dfs2(son[u],tp); for(int i=head[u];i!=-1;i=e[i].next){ int v=e[i].v; if(v!=fa[u] && v!=son[u]) dfs2(v,v); } tidend[u]=idcnt; return; } namespace Segtree{ struct node{ int l,r; LL sum,lazy; }tree[maxn<<2]; void push_up(int rt){ tree[rt].sum=(tree[rt*2].sum+tree[rt*2+1].sum)%mod; } void push_down(int rt){ if(tree[rt].lazy){ int l=tree[rt].l; int r=tree[rt].r; int mid=(l+r)/2; (tree[rt*2].sum+=((tree[rt].lazy)*((mid-l+1)))%mod)%=mod; (tree[rt*2+1].sum+=((tree[rt].lazy)*((r-mid)))%mod)%=mod; (tree[rt*2].lazy+=tree[rt].lazy)%=mod; (tree[rt*2+1].lazy+=tree[rt].lazy)%=mod; tree[rt].lazy=0; } } void build(int l,int r,int rt){ tree[rt].l=l,tree[rt].r=r; if(l==r){ tree[rt].sum=nodew[nrank[l]]*1LL; return; } int mid=(l+r)/2; build(l,mid,rt*2); build(mid+1,r,rt*2+1); push_up(rt); } void add(int l,int r,int rt,int dt){ int tl=tree[rt].l,tr=tree[rt].r; if(l==tl && r==tr){ (tree[rt].lazy+=(dt)*1LL)%=mod; (tree[rt].sum+=((((r-l+1))*(dt))%mod)*1LL)%=mod; return; } push_down(rt); int mid=(tl+tr)/2; if(r<=mid) add(l,r,rt*2,dt); else if(l>mid) add(l,r,rt*2+1,dt); else add(l,mid,rt*2,dt),add(mid+1,r,rt*2+1,dt); push_up(rt); } LL query(int l,int r,int rt){ int tl=tree[rt].l,tr=tree[rt].r; if(tl==l && tr==r) return tree[rt].sum%mod; push_down(rt); int mid=(tl+tr)/2; if(r<=mid) return query(l,r,rt*2)%mod; else if(l>mid) return query(l,r,rt*2+1)%mod; else return (query(l,mid,rt*2)+query(mid+1,r,rt*2+1))%mod; } } LL qsum(int a,int b){ using namespace Segtree; LL ret=0; while(top[a]!=top[b]){ if(d[top[a]]<d[top[b]])swap(a,b); (ret+=query(tid[top[a]],tid[a],1))%=mod; a=fa[top[a]]; } if(d[a]<d[b]) swap(a,b); (ret+=query(tid[b],tid[a],1))%=mod; return ret; } void asum(int a,int b,int dt){ using namespace Segtree; while(top[a]!=top[b]){ if(d[top[a]]<d[top[b]])swap(a,b); add(tid[top[a]],tid[a],1,dt); a=fa[top[a]]; } if(d[a]<d[b]) swap(a,b); add(tid[b],tid[a],1,dt); } void add_subtree(int u,int dt){ Segtree::add(tid[u],tidend[u],1,dt); } LL q_subtree(int u){ return Segtree::query(tid[u],tidend[u],1)%mod; } int main(){ memset(head,-1,sizeof(head)); memset(son,-1,sizeof(son)); scanf("%lld%lld%lld%lld",&n,&m,&root,&mod); for(int i=1;i<=n;i++) scanf("%d",&nodew[i]); for(int i=1;i<=n-1;i++){ int u,v; scanf("%d%d",&u,&v); adde(u,v),adde(v,u); } dfs1(root,0); dfs2(root,root); Segtree::build(1,n,1); while(m--){ int opt,a,b,c; scanf("%d",&opt); if(opt==1){ scanf("%d%d%d",&a,&b,&c); asum(a,b,c); } if(opt==2){ scanf("%d%d",&a,&b); printf("%lld\n",qsum(a,b)); } if(opt==3){ scanf("%d%d",&a,&b); add_subtree(a,b); } if(opt==4){ scanf("%d",&a); printf("%lld\n",q_subtree(a)); } } return 0; }
没有帐号? 立即注册