zoukankan      html  css  js  c++  java
  • bzoj 4765: 普通计算姬

    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

    思路

    分块分块再分块,

    假设块的长度是m,

    可以先对编号分块,预处理出每个点对每一块的贡献(即这一块中有多少个x的祖先)。

    这样时间复杂度n^2/m,空间复杂度n^2/m,为了不mle,m适宜<500。

    这样修改操作就可以O(n/m)完成。

    考虑询问操作,中间的完整块很好处理O(n/m),但左右端的残余块难处理。

    可以扫残余块中的每个点,计算它们子树和的和,大约要计算m次子树和,即查询m次。

    考虑怎样很快的计算子树和。

    一种是log的做法,dfs序建树状数组,修改O(logn),查询O(logn)。但是这样查询多了一个log,不优。

    考虑,每次操作,修改只进行了1次,查询进行了m次。所以考虑使修改变慢,查询变快。

    所以,再对dfs序进行分块即可。这样修改O(n/m),查询1次O(1),非常优越。

    时间复杂度n^2/m+nm=n*(n/m+m)。所以当m=sqrt(n)的时候,时间复杂度为O(n sqrt(n))

    由于这种做法常数较大,虽然是O(n sqrt(n))的,有可能比那些带log的程序要慢(这也很尴尬啊)

    代码

      1 #include <cmath>
      2 #include <cstdio>
      3 #include <iostream>
      4 using namespace std;
      5 int read()
      6 {
      7     char c=getchar();int d=0,f=1;
      8     for(;c<'0'||c>'9';c=getchar())if(c=='-')f=-1;
      9     for(;c>='0'&&c<='9';d=d*10+c-48,c=getchar());
     10     return d*f;
     11 }
     12 typedef unsigned long long ull;
     13 typedef long long ll;
     14 const int N=100002;
     15 int M,n,m,cnt,tot;
     16 int tmp[N],fa[N],bl[N],L[N],R[N],w[N*2],head[N],size[N],pos[N],t[320][N];
     17 ll s[N*2],bs[N*2],a[N*2];
     18 struct xint{int to,next;}e[N*2];
     19 inline void addedge(int x,int y)
     20 {
     21     e[++cnt]=(xint){y,head[x]};
     22     head[x]=cnt;
     23 }
     24 inline void add(int x,int s)
     25 {
     26     for(int i=R[x];i<=R[n];i+=M)a[i]+=s;
     27     for(int i=x;i<=R[x]-1;++i)a[i]+=s; 
     28 }
     29 inline ll ask(int x)
     30 {
     31     int A=pos[x]+size[x]-1,B=pos[x]-1;
     32     return ((A%M)?a[L[A]-1]+a[A]:a[A])-((B%M)?a[L[B]-1]+a[B]:a[B]);
     33 }
     34 inline void dfs(int x)
     35 {
     36     tmp[bl[x]]++;
     37     for(int i=1;i<=bl[n];++i)t[i][x]=tmp[i];
     38     pos[x]=++tot;
     39     size[x]=1; s[x]=w[x];
     40     for(int i=head[x];i;i=e[i].next)
     41     {
     42         int y=e[i].to;
     43         if(y==fa[x])continue;
     44         fa[y]=x;dfs(y);
     45         size[x]+=size[y];
     46         s[x]+=s[y];
     47     }
     48     tmp[bl[x]]--;
     49 }
     50 inline void init()
     51 {
     52     n=read()+1,m=read();
     53     M=int(sqrt(n));
     54     for(int i=1;i<=n;++i)bl[i]=(i-1)/M+1;
     55     for(int i=1;i<=n;++i)L[i]=bl[i]*M-M+1,R[i]=bl[i]*M;
     56     for(int i=2;i<=n;++i)w[i]=read();
     57     for(int i=2;i<=n;++i)
     58     {
     59         int x=read()+1,y=read()+1;
     60         addedge(x,y);
     61         addedge(y,x);
     62     }
     63     dfs(1);
     64     for(int i=1;i<=n;++i)bs[bl[i]]+=s[i];
     65     for(int i=1;i<=n;++i)add(pos[i],w[i]);
     66 }
     67 inline ull solve(int x,int y)
     68 {
     69     ull res=0;
     70     if(bl[x]==bl[y])
     71     {
     72         for(int i=x;i<=y;++i)res+=ask(i);
     73         return res;
     74     }
     75     for(int i=x;i<=R[x];++i)res+=ask(i);
     76     for(int i=L[y];i<=y;++i)res+=ask(i);
     77     for(int i=bl[x]+1;i<=bl[y]-1;++i)res+=bs[i];
     78     return res;
     79 }
     80 inline void work()
     81 {
     82     while(m--)
     83     {
     84         int o=read(),x=read(),y=read();
     85         if(o==1)
     86         {
     87             x++;
     88             ll dw=y-w[x];
     89             for(int i=1;i<=bl[n];++i)
     90                 bs[i]+=dw*t[i][x];
     91             add(pos[x],dw);
     92             w[x]=y;
     93         }else
     94         if(o==2)
     95         {
     96             x++,y++;
     97             ull ans=solve(x,y);
     98             printf("%llu
    ",ans);
     99         }
    100     }
    101 }
    102 int main()
    103 {
    104     init();
    105     work();
    106 }
  • 相关阅读:
    8天学通MongoDB——第三天 细说高级操作
    8天学通MongoDB——第二天 细说增删查改
    8天学通MongoDB——第一天 基础入门
    Redis Web界面管理工具
    Redis 起步
    使用 Swagger UI 与 Swashbuckle 创建 RESTful Web API 帮助文件
    面试应该如何面?
    Login oracle for external authenticate
    突然发现我脾气变好了
    一种持续构建构想
  • 原文地址:https://www.cnblogs.com/Blog-of-Eden/p/6685423.html
Copyright © 2011-2022 走看看