如题,已知一棵包含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取模)
1 #include<algorithm> 2 #include<iostream> 3 #include<cstdlib> 4 #include<cstring> 5 #include<cstdio> 6 #define Rint register int 7 #define mem(a,b) memset(a,(b),sizeof(a)) 8 #define Temp template<typename T> 9 using namespace std; 10 typedef long long LL; 11 const int maxn=200000+10; 12 int n,m,r,mod; 13 //见题意 14 int w[maxn],wt[maxn]; 15 //链式前向星数组,w[]、wt[]初始点权数组 16 int son[maxn],id[maxn],fa[maxn],cnt,dep[maxn],siz[maxn],top[maxn]; 17 //son[]重儿子编号,id[]新编号,fa[]父亲节点,cnt dfs_clock/dfs序,dep[]深度,siz[]子树大小,top[]当前链顶端节点 18 //查询答案 19 struct node 20 { 21 int v,nxt; 22 }G[maxn<<2]; int head[maxn]; int num; 23 struct tre 24 { 25 int l,r,lazy,sum; 26 }tree[maxn<<2]; 27 void add(int u,int v) 28 { 29 G[++num].v=v;G[num].nxt=head[u];head[u]=num; 30 G[++num].v=u;G[num].nxt=head[v];head[v]=num; 31 } 32 void pushdown(int rt,int lenn){ 33 tree[rt<<1].lazy+=tree[rt].lazy; 34 tree[rt<<1|1].lazy+=tree[rt].lazy; 35 tree[rt<<1].sum+=tree[rt].lazy*(lenn-(lenn>>1)); 36 tree[rt<<1|1].sum+=tree[rt].lazy*(lenn>>1); 37 tree[rt<<1].sum%=mod; 38 tree[rt<<1|1].sum%=mod; 39 tree[rt].lazy=0; 40 } 41 42 void build(int l,int r,int root){ 43 tree[root].l=l;tree[root].r=r; 44 tree[root].sum=tree[root].lazy=0; 45 if(l==r){ 46 tree[root].sum=wt[l]; 47 if(tree[root].sum>mod)tree[root].sum%=mod; 48 return; 49 } 50 int mid=l+r>>1; 51 build(l,mid,root<<1); 52 build(mid+1,r,root<<1|1); 53 tree[root].sum=(tree[root<<1].sum+tree[root<<1|1].sum)%mod; 54 } 55 56 int query(int l,int r,int root){ 57 int L=tree[root].l;int R=tree[root].r; 58 if(l<=L&&R<=r){ 59 return tree[root].sum%mod; 60 } 61 if(tree[root].lazy)pushdown(root,R-L+1); 62 int mid=L+R>>1; 63 int ans=0; 64 if(l<=mid) ans+=query(l,r,root<<1),ans%=mod; 65 if(r>mid) ans+=query(l,r,root<<1|1),ans%=mod; 66 return ans; 67 } 68 void update(int l,int r,int val,int root){ 69 int L=tree[root].l;int R=tree[root].r; 70 if(l<=L&&R<=r){ 71 tree[root].lazy+=val; 72 tree[root].sum+=val*(R-L+1); 73 } 74 else{ 75 if(tree[root].lazy)pushdown(root,R-L+1); 76 int mid=L+R>>1; 77 if(l<=mid)update(l,r,val,root<<1); 78 if(r>mid) update(l,r,val,root<<1|1); 79 tree[root].sum=(tree[root<<1].sum+tree[root<<1|1].sum)%mod; 80 } 81 } 82 int qRange(int x,int y){ 83 int ans=0; 84 while(top[x]!=top[y]){//当两个点不在同一条链上 85 if(dep[top[x]]<dep[top[y]])swap(x,y);//把x点改为所在链顶端的深度更深的那个点 86 ans+=query(id[top[x]],id[x],1);//ans加上x点到x所在链顶端 这一段区间的点权和 87 ans%=mod;//按题意取模 88 x=fa[top[x]];//把x跳到x所在链顶端的那个点的上面一个点 89 } 90 //直到两个点处于一条链上 91 if(dep[x]>dep[y])swap(x,y);//把x点深度更深的那个点 92 ans+=query(id[x],id[y],1);//这时再加上此时两个点的区间和即可 93 return ans%mod; 94 } 95 96 void updRange(int x,int y,int k){//同上 97 k%=mod; 98 while(top[x]!=top[y]){ 99 if(dep[top[x]]<dep[top[y]])swap(x,y); 100 update(id[top[x]],id[x],k,1); 101 x=fa[top[x]]; 102 } 103 if(dep[x]>dep[y])swap(x,y); 104 update(id[x],id[y],k,1); 105 } 106 107 void dfs1(int u,int f,int deep){//x当前节点,f父亲,deep深度 108 dep[u]=deep;//标记每个点的深度 109 fa[u]=f;//标记每个点的父亲 110 siz[u]=1;//标记每个非叶子节点的子树大小 111 int maxson=-1;//记录重儿子的儿子数 112 for(int i=head[u];i!=-1;i=G[i].nxt){ 113 int v=G[i].v; 114 if(v==f)continue;//若为父亲则continue 115 dfs1(v,u,deep+1);//dfs其儿子 116 siz[u]+=siz[v];//把它的儿子数加到它身上 117 if(siz[v]>maxson)son[u]=v,maxson=siz[v];//标记每个非叶子节点的重儿子编号 118 } 119 } 120 121 void dfs2(int u,int topf){//x当前节点,topf当前链的最顶端的节点 122 id[u]=++cnt;//标记每个点的新编号 123 wt[cnt]=w[u];//把每个点的初始值赋到新编号上来 124 top[u]=topf;//这个点所在链的顶端 125 if(!son[u])return;//如果没有儿子则返回 126 dfs2(son[u],topf);//按先处理重儿子,再处理轻儿子的顺序递归处理 127 for(int i=head[u];i!=-1;i=G[i].nxt){ 128 int v=G[i].v; 129 if(v==fa[u]||v==son[u])continue; 130 dfs2(v,v);//对于每一个轻儿子都有一条从它自己开始的链 131 } 132 } 133 void init() 134 { 135 memset(head,-1,sizeof(head)); 136 num=-1; 137 } 138 int main(){ 139 init(); 140 scanf("%d%d%d%d",&n,&m,&r,&mod); 141 for(int i=1;i<=n;i++) scanf("%d",&w[i]); 142 for(int i=1;i<n;i++){ 143 int u,v; 144 scanf("%d%d",&u,&v); 145 add(u,v); 146 } 147 dfs1(r,0,1); 148 dfs2(r,r); 149 build(1,n,1); 150 while(m--){ 151 int k,x,y,z; 152 scanf("%d",&k); 153 if(k==1){ 154 scanf("%d%d%d",&x,&y,&z); 155 updRange(x,y,z); 156 } 157 else if(k==2){ 158 scanf("%d%d",&x,&y); 159 printf("%d\n",qRange(x,y)); 160 } 161 else if(k==3){ 162 scanf("%d%d",&x,&y); 163 update(id[x],id[x]+siz[x]-1,y,1); 164 } 165 else{ 166 scanf("%d",&x); 167 printf("%d\n",query(id[x],id[x]+siz[x]-1,1)); 168 } 169 } 170 return 0; 171 }
原文:https://www.cnblogs.com/pangbi/p/12301318.html