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