【BZOJ4372】烁烁的游戏 动态树分治+线段树
【BZOJ4372】烁烁的游戏
Description
背景:烁烁很喜欢爬树,这吓坏了树上的皮皮鼠。
题意:
给定一颗n个节点的树,边权均为1,初始树上没有皮皮鼠。
烁烁他每次会跳到一个节点u,把周围与他距离不超过d的节点各吸引出w只皮皮鼠。皮皮鼠会被烁烁吸引,所以会一直待在节点上不动。
烁烁很好奇,在当前时刻,节点u有多少个他的好朋友---皮皮鼠。
大意:
给一颗n个节点的树,边权均为1,初始点权均为0,m次操作:
Q x:询问x的点权。
M x d w:将树上与节点x距离不超过d的节点的点权均加上w。
Input
第一行两个正整数:n,m
接下来的n-1行,每行三个正整数u,v,代表u,v之间有一条边。
接下来的m行,每行给出上述两种操作中的一种。
Output
对于每个Q操作,输出当前x节点的皮皮鼠数量。
Sample Input
1 2
1 4
1 5
2 3
2 7
5 6
M 1 1 2
Q 5
M 2 2 3
Q 3
M 1 2 1
Q 2
Sample Output
3
6
HINT
数据范围:
n,m<=10^5,|w|<=10^4
注意:w不一定为正整数,因为烁烁可能把皮皮鼠吓傻了。
题解:动态点分治+线段树裸题,每个节点开两棵线段树维护它子树中的以及它的父亲要从它中减去的即可。
注意特判边界的问题。
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int maxn=100010;
int n,m,tot,ans,cnt,mn,rt;
struct sag
{
int ls,rs,sum;
}s[maxn*150];
int to[maxn<<1],next[maxn<<1],head[maxn],siz[maxn],dep[maxn],pos[maxn],md[20][maxn<<1],fa[maxn],Log[maxn<<1];
int r1[maxn],r2[maxn];
bool vis[maxn];
char str[5];
inline void add(int a,int b)
{
to[cnt]=b,next[cnt]=head[a],head[a]=cnt++;
}
void getrt(int x,int fa)
{
int i,tmp=0;
siz[x]=1;
for(i=head[x];i!=-1;i=next[i]) if(!vis[to[i]]&&to[i]!=fa) getrt(to[i],x),siz[x]+=siz[to[i]],tmp=max(tmp,siz[to[i]]);
tmp=max(tmp,tot-siz[x]);
if(tmp<mn) mn=tmp,rt=x;
}
void solve(int x)
{
vis[x]=1;
for(int i=head[x];i!=-1;i=next[i]) if(!vis[to[i]])
tot=siz[to[i]],mn=1<<30,getrt(to[i],x),fa[rt]=x,solve(rt);
}
void dfs(int x,int fa)
{
md[0][++pos[0]]=dep[x],pos[x]=pos[0];
for(int i=head[x];i!=-1;i=next[i]) if(to[i]!=fa)
dep[to[i]]=dep[x]+1,dfs(to[i],x),md[0][++pos[0]]=dep[x];
}
inline int getmin(int a,int b)
{
a=pos[a],b=pos[b];
if(a>b) swap(a,b);
int k=Log[b-a+1];
return min(md[k][a],md[k][b-(1<<k)+1]);
}
inline int dis(int a,int b)
{
return dep[a]+dep[b]-2*getmin(a,b);
}
void updata(int l,int r,int &x,int a,int b)
{
if(a<0) return ;
if(!x) x=++tot;
s[x].sum+=b;
if(l==r) return ;
int mid=(l+r)>>1;
if(a<=mid) updata(l,mid,s[x].ls,a,b);
else updata(mid+1,r,s[x].rs,a,b);
}
int query(int l,int r,int x,int a,int b)
{
if(!x||(a<=l&&r<=b)) return s[x].sum;
int mid=(l+r)>>1;
if(b<=mid) return query(l,mid,s[x].ls,a,b);
if(a>mid) return query(mid+1,r,s[x].rs,a,b);
return query(l,mid,s[x].ls,a,b)+query(mid+1,r,s[x].rs,a,b);
}
inline int rd()
{
int ret=0,f=1; char gc=getchar();
while(gc<'0'||gc>'9') {if(gc=='-') f=-f; gc=getchar();}
while(gc>='0'&&gc<='9') ret=ret*10+(gc^'0'),gc=getchar();
return ret*f;
}
int main()
{
n=rd(),m=rd();
int i,j,x,y,a,b,u;
memset(head,-1,sizeof(head));
for(i=1;i<n;i++) a=rd(),b=rd(),add(a,b),add(b,a);
dfs(1,0),tot=n,mn=1<<30,getrt(1,0),solve(rt),tot=0;
for(j=1;(1<<j)<=2*n-1;j++) for(i=1;i+(1<<j)-1<=2*n-1;i++) md[j][i]=min(md[j-1][i],md[j-1][i+(1<<(j-1))]);
for(i=2;i<=2*n-1;i++) Log[i]=Log[i>>1]+1;
for(i=1;i<=m;i++)
{
scanf("%s",str);
if(str[0]=='Q')
{
u=rd(),ans=0;
for(x=u;x;x=y)
{
y=fa[x];
ans+=query(0,n,r1[x],dis(u,x),n);
if(y) ans-=query(0,n,r2[x],dis(u,y),n);
}
printf("%d\n",ans);
}
else
{
u=rd(),a=rd(),b=rd();
for(x=u;x;x=y)
{
y=fa[x];
updata(0,n,r1[x],min(n,a-dis(u,x)),b);
if(y) updata(0,n,r2[x],min(n,a-dis(u,y)),b);
}
}
}
return 0;
}//7 2 1 2 1 4 1 5 2 3 2 7 5 6 M 1 2 1 Q 2
【BZOJ4372】烁烁的游戏 动态树分治+线段树的更多相关文章
- BZOJ4372烁烁的游戏——动态点分治+线段树(点分树套线段树)
题目描述 背景:烁烁很喜欢爬树,这吓坏了树上的皮皮鼠.题意:给定一颗n个节点的树,边权均为1,初始树上没有皮皮鼠.烁烁他每次会跳到一个节点u,把周围与他距离不超过d的节点各吸引出w只皮皮鼠.皮皮鼠会被 ...
- [bzoj4372] 烁烁的游戏 [动态点分治+线段树+容斥原理]
题面 传送门 思路 观察一下题目,要求的是修改"距离点$u$的距离一定的点权值",那这个就不能用传统的dfs序类算法+线段树维护,因为涉及到向父亲回溯的问题 看到和树上距离相关的东 ...
- [BZOJ4372]烁烁的游戏(动态点分治+线段树)
和[BZOJ3730]震波几乎一样,每个点建两棵线段树分别代表它的管辖范围内以它为LCA的路径的贡献和它对父亲的贡献. 注意点分树上的点的距离在原树上不单调,所以不能有若距离超出限制就break之类的 ...
- 【bzoj4372】烁烁的游戏 动态点分治+线段树
题目描述 给一颗n个节点的树,边权均为1,初始点权均为0,m次操作:Q x:询问x的点权.M x d w:将树上与节点x距离不超过d的节点的点权均加上w. 输入 第一行两个正整数:n,m接下来的n-1 ...
- bzoj 4372: 烁烁的游戏 动态点分治_树链剖分_线段树
[Submit][Status][Discuss] Description 背景:烁烁很喜欢爬树,这吓坏了树上的皮皮鼠. 题意: 给定一颗n个节点的树,边权均为1,初始树上没有皮皮鼠. 烁烁他每次会跳 ...
- BZOJ4372: 烁烁的游戏(动态点分治)
Description 背景:烁烁很喜欢爬树,这吓坏了树上的皮皮鼠.题意:给定一颗n个节点的树,边权均为1,初始树上没有皮皮鼠.烁烁他每次会跳到一个节点u,把周围与他距离不超过d的节点各吸引出w只皮皮 ...
- 【loj6145】「2017 山东三轮集训 Day7」Easy 动态点分治+线段树
题目描述 给你一棵 $n$ 个点的树,边有边权.$m$ 次询问,每次给出 $l$ .$r$ .$x$ ,求 $\text{Min}_{i=l}^r\text{dis}(i,x)$ . $n,m\le ...
- 【bzoj3730】震波 动态点分治+线段树
题目描述 在一片土地上有N个城市,通过N-1条无向边互相连接,形成一棵树的结构,相邻两个城市的距离为1,其中第i个城市的价值为value[i].不幸的是,这片土地常常发生地震,并且随着时代的发展,城市 ...
- UVALive 7148 LRIP【树分治+线段树】
题意就是要求一棵树上的最长不下降序列,同时不下降序列的最小值与最大值不超过D. 做法是树分治+线段树,假设树根是x,y是其当前需要处理的子树,对于子树y,需要处理出两个数组MN,MX,MN[i]表示以 ...
随机推荐
- 【RMAN】使用RMAN增量备份刷新 Standby Database
Step 1: Create the Incremental Backup RMAN> BACKUP DEVICE TYPE DISK INCREMENTAL FROM SCN 750983 D ...
- 2016年第七届蓝桥杯C/C++程序设计本科B组省赛
/* 2016年第七届蓝桥杯C/C++程序设计本科B组省赛 煤球数目(结果填空) 煤球数目 有一堆煤球,堆成三角棱锥形.具体: 第一层放1个, 第二层3个(排列成三角形), 第三层6个(排列成三角形) ...
- 实现整数转化为字符串函数itoa()函数
函数原型: char *itoa( int value, char *string,int radix);原型说明:value:欲转换的数据.string:目标字符串的地址.radix:转换后的进制数 ...
- 判断radiobutton是否被选中
<tr> <td class="label">是否显示:</td> <td> <?php if($cates_data[0][ ...
- Web下的整体测试 --性能测试及优化思路
随着Internet的日益普及,现在基于B/S结构的大型应用越来越多,可如何对这些应用进行测试成为日益迫切的问题.有许多测试人员来信问我B/S的测试如何做,由于工作较繁忙,对大家提出的问题也是头痛医头 ...
- JavaScript 学习笔记(三)
本章学习内容: 1.数组的使用 2.类和对象细节. 3.this关键字的使用 4.构造函数,成员函数的使用 1.数组的使用 在任何的语言中,必须要有的就是数组了,有了数组,使得很多操作都变得非常的 ...
- c网络编程-多播
/* 编译通过环境,Windows XP sp2,Windows 2003 server SDK,VC++6.0 sp5. */ /********************************** ...
- 转载:mysql如果数据不存在,则插入新数据,否则更新的实现方法
转自:http://www.jb51.net/article/28885.htm //如果不存在,则插入新数据 $sql = "INSERT INTO {$ecs->table(‘ca ...
- dwr框架使用总结——简单示例
1.新建web项目,项目名为dwr 2.导入以下jar包: dwr.jar.classes12.jar.commons-logging-1.0.4.jar和commons-logging.jar 3. ...
- 利用jstack 找到异常代码
1.top找出耗时pid进程或ps -ef |grep xxx 找出pid 2.ps p 3036 -L -o pcpu,pid,tid,time,tname,cmd 3036为pid 3.prin ...