普通计算姬

题意:

给出$n$个点的树,记$sum(x)$为$x$子树的点权和。$m$此操作

1.将一个点的权值改为c

2.查询$\sum_{x=l}^r { sum(x)}$

 

解法:

修改一个点 x 的点权会使得从x到root的所有点的$sum(i)$加上一个数字。

考虑对1~n分块,块的大小为$O(\sqrt {\frac{n}{logn}})$。

对于每个块i,计算出$cnt(i,x)$表示如果在x点加上v则$ans(i) = \sum_{j=left}^{right}{sum(j)}$

会加上$cnt(i,x)*v$,这个可以应用dfs序+差分树状数组求出。

对于每组查询,树状数组暴力小块,中间块直接加上$ans(i)$,$O(\sqrt {nlogn})$

对于修改,应用$cnt$实现$O(\sqrt {nlogn})$修改。

注意根据内存限制调整一下块的大小,注意答案炸long long(并不想手写__int128,cpp经本地对拍)。

 

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <cmath>
  5 #include <cstdlib>
  6 
  7 #define LL long long
  8 #define N 100010
  9 #define SIZ 320
 10 #define p E[i].x
 11 #define lbt(x) (x&(-x))
 12 #define MOD 1000000000000000000LL
 13 
 14 using namespace std;
 15 
 16 struct edge
 17 {
 18     int x,to;
 19 }E[N<<1];
 20 
 21 LL ansv[SIZ];
 22 int n,m,tott,totb,totE,root,SIZE;
 23 int g[N],belong[N],L[N],R[N];
 24 int cntv[SIZ][N];
 25 LL d[N];
 26 __int128 sumv[N],ans[N];
 27 
 28 void addedge(int x,int y)
 29 {
 30     E[++totE] = (edge){y,g[x]}; g[x]=totE;
 31     E[++totE] = (edge){x,g[y]}; g[y]=totE;
 32 }
 33 
 34 __int128 ask(int x)
 35 {
 36     __int128 ans;
 37     for(int i=x;i>0;i-=lbt(i))
 38         ans = ans + sumv[i];
 39     return ans;
 40 }
 41 
 42 void add(int x,LL v)
 43 {
 44     for(int i=x;i<=n && i;i+=lbt(i))
 45         sumv[i] += v;
 46 }
 47 
 48 void dfs(int x,int fa)
 49 {
 50     L[x] = ++tott; 
 51     for(int i=g[x];i;i=E[i].to)
 52         if(p!=fa) dfs(p,x);
 53     R[x]=tott;
 54 }
 55 
 56 void com_add(int x,LL v)
 57 {
 58     d[x]+=v;
 59     add(L[x],(LL)v);
 60     for(int t=1;t<=totb;t++)
 61         ans[t] += (cntv[t][x]*(LL)v);
 62 }
 63 
 64 __int128 com_ask(int l,int r)
 65 {
 66     __int128 ansv;
 67     int lb=belong[l],rb=belong[r];
 68     if(lb==rb)
 69     {
 70         for(int i=l;i<=r;i++)
 71             ansv+=ask(R[i])-ask(L[i]-1);
 72         return ansv;
 73     }
 74     for(int i=l;i<=lb*SIZE;i++)
 75         ansv += ask(R[i])-ask(L[i]-1);
 76     for(int i=lb+1;i<rb;i++) ansv += ans[i];
 77     for(int i=(rb-1)*SIZE+1;i<=r;i++)
 78         ansv += ask(R[i])-ask(L[i]-1);
 79     return ansv;
 80 }
 81 
 82 int main()
 83 {
 84     ios::sync_with_stdio(false);
 85     scanf("%d%d",&n,&m);
 86     SIZE=(int)sqrt(n+0.5);
 87     for(int i=1;i<=n;i++) scanf("%lld",&d[i]);
 88     for(int i=1,x,y;i<=n;i++)
 89     {
 90         scanf("%d%d",&x,&y);
 91         if(!x) root=y;
 92         else addedge(x,y);
 93     }
 94     tott=0;
 95     dfs(root,root);
 96     for(int i=1;i<=n;i++) belong[i] = (i-1)/SIZE+1;
 97     totb=belong[n];
 98     for(int t=1;t<=totb;t++)
 99     {
100         for(int i=(t-1)*SIZE+1;i<=min(t*SIZE,n);i++)
101         {
102             add(L[i],1);
103             add(R[i]+1,-1);
104         }
105         for(int i=1;i<=n;i++)
106             cntv[t][i]=(int)ask(L[i]).b;
107         for(int i=(t-1)*SIZE+1;i<=min(t*SIZE,n);i++)
108         {
109             add(L[i],-1);
110             add(R[i]+1,1);
111         }
112     }
113     for(int i=1;i<=n;i++) add(L[i],d[i]);
114     for(int i=1;i<=totb;i++) ans[i].a=ans[i].b=0;
115     for(int i=1;i<=n;i++)
116         ans[belong[i]] += ask(R[i])-ask(L[i]-1);
117     for(int i=1,cmd,x;i<=m;i++)
118     {
119         LL v;
120         scanf("%d%d%lld",&cmd,&x,&v);
121         if(cmd==1) com_add(x,v-d[x]);
122         else cout << com_ask(x,v) << endl;
123     }
124     return 0;
125 }
126 /*
127 6 4
128 0 0 3 4 0 1
129 0 1
130 1 2
131 2 3
132 2 4
133 3 5
134 5 6
135 2 1 2
136 1 1 1
137 2 3 6
138 2 3 5
139 */
View Code

 

转载于:https://www.cnblogs.com/lawyer/p/6520391.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值