• 【2018沈阳赛区网络预选赛J题】Ka Chang【分块+DFS序+线段树】


    题意

      给出一个有根树(根是1),有n个结点。初始的时候每个结点的值都是0.下面有q个操作,操作有两种,操作1.将深度为L的点的值全部增加X。操作2.查询以x为根的子树的结点值得和。

     其中N,Q<=1e5

    分析

      一看这种没有办法直接用数据结构解决得问题就要考虑分块。这个题其实也不算是分块,应该是用了分块的思想进行分类而已。场上也一直在想分块但是可能是自己太菜了,赛后看了题解补的。

      分块最重要的就是算时间复杂度啊。我们按照每一层的结点数进行分类。节点数>block的为第一类,节点数<=为第二类。

      对于第二类,每次修改操作我们暴力修改每个结点的影响值,因为涉及线段树或者树状数组的操作,时间复杂度为O(q*block*logn)。而每次通过线段树查询都是logn的

      对于第一类,当修改的时候直接记录这一层被增加了多少,O(1)修改,然后查询的时候只需要枚举第二类的每一层,然后以这个结点为根节点的子树中属于这一层的节点数*这一层增加的值。这里的时间复杂度是O(q*n/block)

      我们需要预处理出每个结点的子树中属于第一类层的节点数各有多少。这里我用的办法就是直接暴力。枚举每个点,如果它所在的层是第一类,那么更新它所有的父节点。这里的时间复杂度很容易被认为是O(n^2)(所以我一直不打敢写)。但是我们仔细分析一下发现它远远小于O(n^2)。因为最多有n/block层,所以这里的时间复杂度是O(n*n/block)

     先不考虑预处理,只看操作的时间复杂度是O(q*block*logn+q*n/block).根据均值不等式最小是O(q*2*sqrt(nlogn)),当且仅当block取sqrt(n/logn)。这时候预处理的时间复杂度是O(n*sqrt(n*logn))经过计算时可以承受的(因为只有单组数据)。

       这种题目时间复杂度计算明白以后写起来还是很好写的

         

      1 #include <cstdio>
      2 #include <algorithm>
      3 #include <cstring>
      4 #include <iostream>
      5 #include <queue>
      6 #include <cmath>
      7 #include <map>
      8 #include <vector>
      9 
     10 using namespace std;
     11 typedef long long LL;
     12 const int maxn=100000+100;
     13 int head[maxn],to[maxn*2],Next[2*maxn],Fa[maxn];
     14 int n,q,sz,block,maxd;
     15 int order[maxn],R[maxn],num,belong[maxn],L[maxn],pos[maxn];
     16 
     17 map<int,int>M[maxn];
     18 LL addv[maxn],sumv[4*maxn];
     19 vector<int>deep[maxn];
     20 void init(){
     21     sz=-1;
     22     maxd=0;
     23     num=0;
     24 //    for(int i=0;i<=n;i++)M[i].clear();
     25 //    for(int i=0;i<=n;i++)deep[i].clear();
     26     memset(head,-1,sizeof(head));
     27 //    memset(addv,0,sizeof(addv));
     28 }
     29 void add_edge(int a,int b){
     30     ++sz;
     31     to[sz]=b;Next[sz]=head[a];head[a]=sz;
     32 }
     33 
     34 void dfs(int u,int fa,int dep){
     35     maxd=max(maxd,dep);
     36     Fa[u]=fa;
     37     num++;
     38     order[num]=u;L[u]=num;belong[u]=dep;pos[u]=num;
     39     deep[dep].push_back(u);
     40     for(int i=head[u];i!=-1;i=Next[i]){
     41         int v=to[i];
     42         if(v==fa)continue;
     43         dfs(v,u,dep+1);
     44     }
     45     R[u]=num;
     46 }
     47 int p,v;
     48 void update(int o,int L,int R){
     49     if(L==R){
     50         sumv[o]+=v;
     51         return ;
     52     }
     53     int M=L+(R-L)/2;
     54     if(p<=M)
     55         update(2*o,L,M);
     56     if(p>M)
     57         update(2*o+1,M+1,R);
     58     sumv[o]=sumv[2*o]+sumv[2*o+1];
     59 }
     60 int ql,qr;
     61 LL res;
     62 void query(int o,int L,int R){
     63     if(ql<=L&&qr>=R){
     64         res+=sumv[o];
     65         return ;
     66     }
     67     int M=L+(R-L)/2;
     68     if(ql<=M)
     69         query(2*o,L,M);
     70     if(qr>M)
     71         query(2*o+1,M+1,R);
     72 }
     73 LL ask(int root){
     74     LL res=0;
     75     map<int,int>::iterator it;
     76     for(it=M[root].begin();it!=M[root].end();it++){
     77         res+=(LL)it->second*addv[it->first];
     78     }
     79     return res;
     80 }
     81 int main(){
     82     scanf("%d%d",&n,&q);
     83     init();
     84     int a,b,c;
     85     for(int i=1;i<n;i++){
     86         scanf("%d%d",&a,&b);
     87         add_edge(a,b);
     88     }
     89     dfs(1,-1,0);
     90     block=sqrt(n/log(n));
     91     num=0;
     92     for(int i=1;i<=n;i++){
     93         if(deep[belong[i]].size()>block){
     94             int u=i;
     95             while(u!=-1){
     96                 if(!M[u].count(belong[i]))
     97                     M[u][belong[i]]=1;
     98                 else
     99                     M[u][belong[i]]++;
    100                 u=Fa[u];
    101             }
    102         }
    103     }
    104     for(int i=1;i<=q;i++){
    105         scanf("%d",&a);
    106         if(a==1){
    107             scanf("%d%d",&b,&c);
    108             if(deep[b].size()>block){
    109                 addv[b]+=c;
    110             }else{
    111                 for(int j=0;j<deep[b].size();j++){
    112                     int u=deep[b][j];
    113                     p=pos[u],v=c;
    114                     update(1,1,n);
    115                 }
    116             }
    117         }else{
    118             scanf("%d",&b);
    119             res=0;
    120             ql=L[b],qr=R[b];
    121             query(1,1,n);
    122             LL ans=res+ask(b);
    123             printf("%lld
    ",ans);
    124         }
    125     }
    126 
    127 return 0;
    128 }
    View Code
  • 相关阅读:
    eg_5
    浅谈Java中的Hashmap
    java中方法传入参数时:值传递还是址传递?
    重温概率学(一)期望、均值、标准差、方差
    博客搬家
    golang sync/atomic
    单机配置kafka和zookeeper
    异步消息队列组件
    2017总结
    看完轻松年薪30w+
  • 原文地址:https://www.cnblogs.com/LQLlulu/p/9625542.html
Copyright © 2020-2023  润新知