题意

给出一个有根树(根是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))经过计算时可以承受的(因为只有单组数据)。

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

 #include <cstdio>
#include <algorithm>
#include <cstring>
#include <iostream>
#include <queue>
#include <cmath>
#include <map>
#include <vector> using namespace std;
typedef long long LL;
const int maxn=+;
int head[maxn],to[maxn*],Next[*maxn],Fa[maxn];
int n,q,sz,block,maxd;
int order[maxn],R[maxn],num,belong[maxn],L[maxn],pos[maxn]; map<int,int>M[maxn];
LL addv[maxn],sumv[*maxn];
vector<int>deep[maxn];
void init(){
sz=-;
maxd=;
num=;
// for(int i=0;i<=n;i++)M[i].clear();
// for(int i=0;i<=n;i++)deep[i].clear();
memset(head,-,sizeof(head));
// memset(addv,0,sizeof(addv));
}
void add_edge(int a,int b){
++sz;
to[sz]=b;Next[sz]=head[a];head[a]=sz;
} void dfs(int u,int fa,int dep){
maxd=max(maxd,dep);
Fa[u]=fa;
num++;
order[num]=u;L[u]=num;belong[u]=dep;pos[u]=num;
deep[dep].push_back(u);
for(int i=head[u];i!=-;i=Next[i]){
int v=to[i];
if(v==fa)continue;
dfs(v,u,dep+);
}
R[u]=num;
}
int p,v;
void update(int o,int L,int R){
if(L==R){
sumv[o]+=v;
return ;
}
int M=L+(R-L)/;
if(p<=M)
update(*o,L,M);
if(p>M)
update(*o+,M+,R);
sumv[o]=sumv[*o]+sumv[*o+];
}
int ql,qr;
LL res;
void query(int o,int L,int R){
if(ql<=L&&qr>=R){
res+=sumv[o];
return ;
}
int M=L+(R-L)/;
if(ql<=M)
query(*o,L,M);
if(qr>M)
query(*o+,M+,R);
}
LL ask(int root){
LL res=;
map<int,int>::iterator it;
for(it=M[root].begin();it!=M[root].end();it++){
res+=(LL)it->second*addv[it->first];
}
return res;
}
int main(){
scanf("%d%d",&n,&q);
init();
int a,b,c;
for(int i=;i<n;i++){
scanf("%d%d",&a,&b);
add_edge(a,b);
}
dfs(,-,);
block=sqrt(n/log(n));
num=;
for(int i=;i<=n;i++){
if(deep[belong[i]].size()>block){
int u=i;
while(u!=-){
if(!M[u].count(belong[i]))
M[u][belong[i]]=;
else
M[u][belong[i]]++;
u=Fa[u];
}
}
}
for(int i=;i<=q;i++){
scanf("%d",&a);
if(a==){
scanf("%d%d",&b,&c);
if(deep[b].size()>block){
addv[b]+=c;
}else{
for(int j=;j<deep[b].size();j++){
int u=deep[b][j];
p=pos[u],v=c;
update(,,n);
}
}
}else{
scanf("%d",&b);
res=;
ql=L[b],qr=R[b];
query(,,n);
LL ans=res+ask(b);
printf("%lld\n",ans);
}
} return ;
}

【2018沈阳赛区网络预选赛J题】Ka Chang【分块+DFS序+线段树】的更多相关文章

  1. 【2018沈阳赛区网络预选赛J题】Fantastic Graph 【有上下界的网络流】

    要补的题太多了导致最近没写博客(好吧是我懒) 题目链接https://nanti.jisuanke.com/t/31447 题意 给出一个二分图,问能否挑选出一些边,使得每个点的度数都在[L,R]这个 ...

  2. ACM-ICPC 2018 沈阳赛区网络预赛 J树分块

    J. Ka Chang Given a rooted tree ( the root is node 11 ) of NN nodes. Initially, each node has zero p ...

  3. ACM-ICPC 2018 焦作赛区网络预赛J题 Participate in E-sports

    Jessie and Justin want to participate in e-sports. E-sports contain many games, but they don't know ...

  4. ACM-ICPC 2018 沈阳赛区网络预赛 J Ka Chang

    Ka Chang 思路: dfs序+树状数组+分块 先dfs处理好每个节点的时间戳 对于每一层,如果这一层的节点数小于sqrt(n),那么直接按照时间戳在树状数组上更新 如果这一层节点个数大于sqrt ...

  5. ACM-ICPC 2018 沈阳赛区网络预赛 J. Ka Chang(树上分块+dfs序+线段树)

    题意 链接:https://nanti.jisuanke.com/t/A1998 给出一个有根树(根是1),有n个结点.初始的时候每个结点的值都是0.下面有q个操作,操作有两种,操作1.将深度为L(根 ...

  6. ACM-ICPC 2018 南京赛区网络预赛 G Lpl and Energy-saving Lamps(模拟+线段树)

    https://nanti.jisuanke.com/t/30996 题意 每天增加m个灯泡,n个房间,能一次性换就换,模拟换灯泡过程.询问第几天的状态 分析 离线做,按题意模拟.比赛时线段树写挫了. ...

  7. 计蒜客A1998 Ka Chang (分块+dfs序+树状数组)

    题意 给你一个\(1e5\)的有点权的树,有\(1e5\)个操作: 1.给第\(x\)层的点加上\(y\) 2.求以\(x\)为根的子树的点权和 思路 首先处理出层数为x的所有点 操作2一般都是用df ...

  8. ACM-ICPC 2018 沈阳赛区网络预赛 J. Ka Chang (分块思想)

    题目链接:https://nanti.jisuanke.com/t/31451 题意: 给你一颗树,树上各点有初始权值,你有两种操作: 1. 给树中深度为l的点全部+x,(根节点为1,深度为0) 2. ...

  9. ACM-ICPC 2018 沈阳赛区网络预赛 J. Ka Chang(树状数组+分块)

    Given a rooted tree ( the root is node 1 ) of N nodes. Initially, each node has zero point. Then, yo ...

随机推荐

  1. Serf 了解

    Introduction to Serf Welcome to the intro guide to Serf! This guide will show you what Serf is, expl ...

  2. element popover 不显示/不隐藏问题解决方法

    html代码部分 <el-table-column label="操作"> <template slot-scope="scope"> ...

  3. Centos下 yum方式安装LAMP

    首先安装apache    centos可以直接yum安装apache . 配置网易163 yum源  http://www.cnblogs.com/carbon3/p/5635403.html 一. ...

  4. 记录:Web无引用无配置方式动态调用WCF服务

    这几年一直用WebApi较多,最近项目中有个需求比较适合使用WCF,以前也用过JQuery直接调用Wcf的,但是说实话真的忘了… 所以这次解决完还是花几分钟记录一下 WCF服务端:宿主在现有Win服务 ...

  5. python 异常处理,约束

    异常处理: 在编程过程中为了增加友好性,在程序出现bug时一般不会将错误信息显示给用户,而是显示一个提示的页面. try: pass except Exception,ex: pass 例如: whi ...

  6. Java经典练习题_Day05

    一. 选择题 1.下列各项中的各项定义正确的是:(ACD) A.  public static void m(){}   B.  public void static m(){} C.  public ...

  7. Redis: temple

    ylbtech-Redis:  1.返回顶部   2.返回顶部   3.返回顶部   4.返回顶部   5.返回顶部     6.返回顶部   7.返回顶部   8.返回顶部   9.返回顶部   1 ...

  8. python学习 (二十八) Python的for 循环

    1: for 循环可以循环如下类型: my_string = "abcabc" // 字符串类型 for c in my_string: print(c, end=' ') car ...

  9. 在虚拟机里新建一个20G的硬盘,如何把他挂载在 /work 目录上

    目的:在虚拟机里新建一个20G的硬盘,然后想把他挂载在 /work 目录上 /dev/sda (系统盘) /dev/sdb (数据盘) /dev/sdc (数据盘) /dev/sdd (数据盘) /d ...

  10. 【BZOJ】1912: [Apio2010]patrol 巡逻(树的直径)

    题目 传送门:QWQ 分析 $ k=1 $ 时显然就是树的直径 $ k=2 $ 时怎么做呢? 做法是把一开始树的直径上的边的边权改成$ -1 $,那么当我们第二次用这些边做环时就抵消了一开始的贡献. ...