题意

链接:https://nanti.jisuanke.com/t/A1998

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

思路

因为这题是对某一深度的所有点加x,所以不是树链剖分。

我们可以先预处理一下dfs序,顺带把d[u]:u的深度、dd[x]:深度为x的点集求出来。

考虑分块,对某一深度分两种情况:1.这一深度的点的个数<=block;2.这一深度的点的个数>block。

对于情况1:更新操作我们可以暴力,因为block我是取的sqrt(n),那么更新的复杂度最坏也是O(qlog(n)sqrt(n)),还能接受,毕竟数据不是特别强。

对于情况2:我们直接将这一层加上x,即add[deep]+=x。

对于查询操作,我们先线段树计算一下这个点为根的子树的值,当然,线段树只暴力更新了size<=block的层,所以查询也只会查询这些层上的值。我们还要计算一下size>block的层,怎么计算呢?

我们先定义一个map<ll,ll> M[N],M[u]表示u为根节点的子树的值的和(size>block的层),M可以通过枚举每个点,如果这个点所在层的size>block,这个点就对它的所有父亲都有贡献,所以往上爬,对父亲加上这个点的贡献。所以size>block的层的值我们可以轻松通过M来得到。

代码

#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
#define ll long long
#define int ll
const int N=200005;
const double eps=1e-8;
const double PI = acos(-1.0);
struct node
{
int to,next;
} eg[N];
int head[N],tot=0,sum[N<<2],add[N];
void init()
{
memset(head,-1,sizeof(head));
tot=0;
}
void addedge(int u,int v)
{
eg[tot].to=v;
eg[tot].next=head[u];
head[u]=tot++;
}
int in[N],out[N],id=0,q[N],d[N],block,f[N];
vector<int> dd[N];
map<ll,ll> M[N];
void dfs(int x,int fa,int deep)
{
q[++id]=x;
in[x]=id;
d[x]=deep;
f[x]=fa;
dd[deep].push_back(x);
for(int i=head[x]; ~i; i=eg[i].next)
{
if(eg[i].to!=fa)
{
dfs(eg[i].to,x,deep+1);
}
}
out[x]=id;
}
void pushUp(int rt)
{
sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
void build(int l,int r,int rt)
{
if(l==r)
{
sum[rt]=0;
return;
}
int m=(l+r)>>1;
build(l,m,rt<<1);
build(m+1,r,rt<<1|1);
pushUp(rt);
}
void update(int L,int c,int l,int r,int rt)
{
if(l==r)
{
sum[rt]+=c;
return ;
}
int m=(l+r)>>1;
if(m>=L) update(L,c,l,m,rt<<1);
else update(L,c,m+1,r,rt<<1|1);
pushUp(rt); }
int query(int L,int R,int l,int r,int rt)
{
if(l>=L&&r<=R)
{
return sum[rt];
}
int m=(l+r)>>1;
int ans=0;
if(m>=L)
ans+=query(L,R,l,m,rt<<1);
if(m<R)
ans+=query(L,R,m+1,r,rt<<1|1);
return ans;
}
ll ask(int rt)
{
map<ll,ll>::iterator it=M[rt].begin();
ll res=0;
for(;it!=M[rt].end();it++)
{
res+=(it->second)*add[it->first];
}
return res;
}
signed main()
{
std::ios::sync_with_stdio(false);
std::cin.tie(0);
std::cout.tie(0);
int n,q;
while(cin>>n>>q)
{
id=0;
memset(in,0,sizeof(in));
memset(out,0,sizeof(out));
init();
for(int i=0; i<n-1; i++)
{
int a,b;
cin>>a>>b;
addedge(a,b);
addedge(b,a);
}
block=sqrt(n);
dfs(1,0,0);
build(1,n,1);
for(int i=1; i<=n; i++)
{
if(dd[d[i]].size()>block)
{
int u=i;
while(u)
{
if(!M[u][d[i]])
M[u][d[i]]=1;
else
M[u][d[i]]++;
u=f[u];
}
}
}
// for(int i=1;i<=n;i++)
// cout<<i<<" "<<in[i]<<" "<<out[i]<<endl;
while(q--)
{
int o,a,b;
cin>>o>>a;
if(o==1)
{
cin>>b;
if(dd[a].size()>block)
{
add[a]+=b;
}
else
{
int sz=dd[a].size();
for(int i=0;i<sz;i++)
{
int u=dd[a][i];
update(in[u],b,1,n,1);
}
}
}
else
{ cout<<query(in[a],out[a],1,n,1)+ask(a)<<endl;
}
}
}
return 0;
}

ACM-ICPC 2018 沈阳赛区网络预赛 J. Ka Chang(树上分块+dfs序+线段树)的更多相关文章

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

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

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

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

  3. 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 ...

  4. ACM-ICPC 2018 沈阳赛区网络预赛 J. Ka Chang (树分块)

    题意:一个树,支持两种操作:1.将深度为L的节点权置加上X;2.求以x为根节点的子树上节点权置之和.根节点深度为0. 分析:考虑用树状数组维护节点权置,按dfs序下标查询.记录每个深度节点的个数.如果 ...

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

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

  6. 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 ...

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

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

  8. ACM-ICPC 2018 徐州赛区网络预赛 J. Maze Designer (最大生成树+LCA求节点距离)

    ACM-ICPC 2018 徐州赛区网络预赛 J. Maze Designer J. Maze Designer After the long vacation, the maze designer ...

  9. ACM-ICPC 2018 沈阳赛区网络预赛 K Supreme Number(规律)

    https://nanti.jisuanke.com/t/31452 题意 给出一个n (2 ≤ N ≤ 10100 ),找到最接近且小于n的一个数,这个数需要满足每位上的数字构成的集合的每个非空子集 ...

随机推荐

  1. Nginx一般配置

    文件为 nginx.conf ,一般配置内容如下: user root;worker_processes auto;#pid /var/run/nginx.pid;#error_log /dev/st ...

  2. 如何判断Linux系统安装在VMware上?

    如何判断当前Linux系统是否安装在VMware上面呢? 因为公司大部分服务器位于VMware上,也有小部分系统部署在物理机上面.今天老大要求统计一下VMware和物理机上服务器的数量,个人简单测试. ...

  3. Linux—修改文件权限、文件拥有者以及文件所在组

    修改文件权限——chmod 修改文件拥有者——chown 修改文件所属组群——chgrp

  4. java8-13-默认方法 静态方法 重复注解 类型注解

    java8增加默认方法 静态方法   重复注解 类型注解   1.默认方法 default修饰   为什么要有这个特性? 当修改接口时候,需要修改全部实现该接口的类.为了解决这个问题,所以引进默认方法 ...

  5. MySQL 的 4 种隔离级别,你了解么?

    1.什么是事务 事务是应用程序中一系列严密的操作,所有操作必须成功完成,否则在每个操作中所作的所有更改都会被撤消.也就是事务具有原子性,一个事务中的一系列的操作要么全部成功,要么一个都不做.事务的结束 ...

  6. Codeforces Round #578 (Div. 2)

    Codeforces Round #578 (Div. 2) 传送门 A. Hotelier 暴力即可. Code #include <bits/stdc++.h> using names ...

  7. R的环境系统

      r环境概念 环境:用来具体存储对象的地方. 规则1:每一个对象都存储在一个环境当中. 规则2:每一个环境都与一个父环境相连接,构成一个分层的环境系统. 规则3:子环境与父环境的连接是单向的. pa ...

  8. php处理curl的返回结果

    最简单的方式: json_decode($res,true): 结果都是:

  9. Elasticsearch 6.x版本全文检索学习之Search API

    Elasticsearch 6.x版本全文检索学习之Search API. 1).Search API,实现对es中存储的数据进行查询分析,endpoind为_search,如下所示. 方式一.GET ...

  10. SpringBoot(14)—注解装配Bean

    SpringBoot(14)-注解装配Bean SpringBoot装配Bean方式主要有两种 通过Java配置文件@Bean的方式定义Bean. 通过注解扫描的方式@Component/@Compo ...