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 }
View Code

 

posted @ 2020-07-14 22:09  古比  阅读(172)  评论(0编辑  收藏  举报