zoukankan      html  css  js  c++  java
  • 【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
  • 相关阅读:
    Leetcode 16.25 LRU缓存 哈希表与双向链表的组合
    Leetcode437 路径总和 III 双递归与前缀和
    leetcode 0404 二叉树检查平衡性 DFS
    Leetcode 1219 黄金矿工 暴力回溯
    Leetcode1218 最长定差子序列 哈希表优化DP
    Leetcode 91 解码方法
    Leetcode 129 求根到叶子节点数字之和 DFS优化
    Leetcode 125 验证回文串 双指针
    Docker安装Mysql记录
    vmware虚拟机---Liunx配置静态IP
  • 原文地址:https://www.cnblogs.com/LQLlulu/p/9625542.html
Copyright © 2011-2022 走看看