zoukankan      html  css  js  c++  java
  • [BZOJ4765]普通计算姬(分块+树状数组)

    4765: 普通计算姬

    Time Limit: 30 Sec  Memory Limit: 256 MB
    Submit: 1725  Solved: 376
    [Submit][Status][Discuss]

    Description

    "奋战三星期,造台计算机"。小G响应号召,花了三小时造了台普通计算姬。普通计算姬比普通计算机要厉害一些
    。普通计算机能计算数列区间和,而普通计算姬能计算树中子树和。更具体地,小G的计算姬可以解决这么个问题
    :给定一棵n个节点的带权树,节点编号为1到n,以root为根,设sum[p]表示以点p为根的这棵子树中所有节点的权
    值和。计算姬支持下列两种操作:
    1 给定两个整数u,v,修改点u的权值为v。
    2 给定两个整数l,r,计算sum[l]+sum[l+1]+....+sum[r-1]+sum[r]
    尽管计算姬可以很快完成这个问题,可是小G并不知道它的答案是否正确,你能帮助他吗?

    Input

    第一行两个整数n,m,表示树的节点数与操作次数。
    接下来一行n个整数,第i个整数di表示点i的初始权值。
    接下来n行每行两个整数ai,bi,表示一条树上的边,若ai=0则说明bi是根。
    接下来m行每行三个整数,第一个整数op表示操作类型。
    若op=1则接下来两个整数u,v表示将点u的权值修改为v。
    若op=2则接下来两个整数l,r表示询问。
    N<=10^5,M<=10^5
    0<=Di,V<2^31,1<=L<=R<=N,1<=U<=N

    Output

    对每个操作类型2输出一行一个整数表示答案。

    Sample Input

    6 4
    0 0 3 4 0 1
    0 1
    1 2
    2 3
    2 4
    3 5
    5 6
    2 1 2
    1 1 1
    2 3 6
    2 3 5

    Sample Output

    16
    10
    9

    HINT

    Source

    [Submit][Status][Discuss]

    因为每个点的编号都是给定的,所以任何基于连续序列的数据结构(如DFS序等)都会失效(听说KDT可做),于是分块。

    然后分块也是有讲究的,这题用到了一个套路:f[i][j]表示节点i到根的路径上的有多少个点在第j块中(也就是修改i节点对第j块的贡献),这个直接DFS预处理出来即可。

    这样我们整块直接使用f数组,两端暴力上DFS序+树状数组即可。

    友情提醒:这题爆long long 。

     1 #include<cmath>
     2 #include<cstdio>
     3 #include<algorithm>
     4 #define rep(i,l,r) for (int i=l; i<=r; i++)
     5 #define For(i,x) for (int i=h[x],k; i; i=nxt[i])
     6 typedef unsigned long long ll;
     7 using namespace std;
     8 
     9 const int N=100100;
    10 int n,m,bl,B,u,v,l,r,cnt,tim,op,rt;
    11 int h[N],a[N],bel[N],nxt[N<<1],L[N],R[N],to[N<<1],f[N][320];
    12 ll c[N],sm[320],s[N],ans;
    13 void ins(int u,int v){ to[++cnt]=v; nxt[cnt]=h[u]; h[u]=cnt; }
    14 
    15 void add(int x,ll k){ for (; x<=n; x+=x&-x) c[x]+=k; }
    16 ll que(int x){ ll res=0; for (; x; x-=x&-x) res+=c[x]; return res; }
    17 
    18 void dfs(int x,int fa){
    19     rep(i,1,B) f[x][i]=f[fa][i];
    20     f[x][bel[x]]++; L[x]=++tim; s[x]=a[x];
    21     For(i,x) if ((k=to[i])!=fa) dfs(k,x),s[x]+=s[k];
    22     R[x]=tim;
    23 }
    24 
    25 int main(){
    26     freopen("bzoj4765.in","r",stdin);
    27     freopen("bzoj4765.out","w",stdout);
    28     scanf("%d%d",&n,&m); bl=(int)sqrt(n); B=(n-1)/bl+1;
    29     rep(i,1,n) scanf("%d",&a[i]),bel[i]=(i-1)/bl+1;
    30     rep(i,1,n){
    31         scanf("%d%d",&u,&v);
    32         if (u==0) rt=v; else ins(u,v),ins(v,u);
    33     }
    34     dfs(rt,0); rep(i,1,n) sm[bel[i]]+=s[i],add(L[i],a[i]);
    35     rep(i,1,m){
    36         scanf("%d",&op);
    37         if (op==1){
    38             scanf("%d%d",&u,&v); add(L[u],v-a[u]);
    39             rep(i,1,B) sm[i]+=1ll*(v-a[u])*f[u][i]; a[u]=v;
    40         }else{
    41             scanf("%d%d",&l,&r); ans=0; int x=bel[l],y=bel[r];
    42             if (x==y) rep(i,l,r) ans+=que(R[i])-que(L[i]-1);
    43             else{
    44                 rep(i,l,x*bl) ans+=que(R[i])-que(L[i]-1);
    45                 rep(i,(y-1)*bl+1,r) ans+=que(R[i])-que(L[i]-1);
    46                 rep(i,x+1,y-1) ans+=sm[i];
    47             }
    48             printf("%llu
    ",ans);
    49         }
    50     }
    51     return 0;
    52 }
  • 相关阅读:
    转 sql 时间转换格式 convert(varchar(10),字段名,转换格式)
    C#页面添加提交数据后跳出小弹窗的功能
    解决粘包问题
    粘包问题
    模拟ssh远程执行命令
    基于TCP协议的socket套接字编程
    Linux和git使用
    osi七层协议
    TCP协议的三次握手和四次挥手
    C/S 和 B/S架构
  • 原文地址:https://www.cnblogs.com/HocRiser/p/8797701.html
Copyright © 2011-2022 走看看