题意

给出一个有根树(根是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. python 中的异常处理

    refer to: http://www.runoob.com/python/python-exceptions.html http://www.pythondoc.com/pythontutoria ...

  2. C#.NET抽象类和接口的区别?

    声明方法的存在而不去实现它的类被叫做抽象类(abstract class),它用于要创建一个体现某些基本行为的类,并为该类声明方法,但不能在该类中实现该类的情况.不能创建abstract 类的实例.然 ...

  3. 解决Vsphere Client 60天过期问题

  4. L2TP/IPSec一键安装脚本

    本脚本适用环境:系统支持:CentOS6+,Debian7+,Ubuntu12+内存要求:≥128M更新日期:2017 年 05 月 28 日 关于本脚本:名词解释如下L2TP(Layer 2 Tun ...

  5. AppScan9.0.3.5漏洞扫描记录

    1.跨站点脚本编制 这个安全漏洞拿cookie做文章,而且是将前端的一些弹窗方法,要么通过脚本注入,要么通过url.encode之后注入,看几个变异的版本: 版本一: cookie  从以下位置进行控 ...

  6. Python函数 hash()

    hash(object)    hash() 用于获取取一个对象(字符串或者数值等)的哈希值.返回对象的哈希值.  实例: >>>hash('test') # 字符串 2314058 ...

  7. 搭建一个IntelliJ的Spark项目

    之前发现创建一个新项目之后,无法添加scala class 创建新项目 选择maven项目,然后选择simple或者quickstart: 进入项目后,在Project Structure里面,在gl ...

  8. (新)解决php版本ueditor中动态配置图片URL前缀(imageurlprefix)的方法

    昨天晚上写了一篇文章<解决ueditor中没法动态配置imageurlprefix的方法>,通过修改js获取当前域名的方法,配置imageurlprefix值: 发现还是不够灵活,因为域名 ...

  9. 用活Firewalld防火墙之direct

    原文地址:http://www.excelib.com/article/294/show 学生在前面已经给大家介绍过了Firewalld中direct的作用,使用他可以直接使用iptables.ip6 ...

  10. rtmp直播推流(一)--flv格式解析与封装

    flv文件格式分析,可参看RTMP中FLV流到标准h264.aac的转换,该文章写的很清晰. flv封装格式解析,可参看视音频数据处理入门:FLV封装格式解析,文章图文并貌,很直观. flv文件封装, ...