【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]表示以 ...
随机推荐
- JavaScript(一):JavaScript简介
一.什么是JavaScript JavaScript是一种具有面向对象能力的.解释性的程序设计语言.更具体一点,它是基于对象和事件驱动并具有相对安全性的客户端脚本语言.因为他不需要在一个语言环境下运行 ...
- MySql C++调用库Connector/c++编译 和 接口封装【三】Connector/c++ 使用总结及封装
工程需要加上各个路径: 库使用需要几个文件: 1.include 文件夹 c/c++ /常规/附加包含目录 Connector/c++ 的安装版里面的Include 文件夹.或者把 /driver以及 ...
- js学习笔记13----数组的操作
1.数组的定义 格式1:var arr=[1,2,3]; 格式2:var arr=new Array(1,2,3); //new可以省略 注意:var arr=new Array(4);如果你里面只写 ...
- 【转】【MFC】 StretchBlt绘图图像失真
MFC中位图伸缩函数StretchBlt在对图片进行缩放时会造成严重的图片失真. 在了解解决方法前先巩固下StretchBlt的用法: StretchBlt 函数功能:函数从源矩形中复制一个位图到目标 ...
- mysql 从sql存储文件恢复数据库乱码
场景一: 一台电脑上导出的sql文件到另一台电脑上恢复数据库,汉字全部是乱码,然后可能还有部分数据提示超长. 场景二: 拿到的sql文件不是原始的导出sql文件,只有表结构和表数据,出现的问题和场景一 ...
- C# 使用IrisSkin2.dll皮肤库C# ssk皮肤
其实皮肤就是一个第三方的控件,名字是IrisSkin2.dll只要添加到你的工具箱里就可以和其它控件一样使用了下面我说一下使用的方法,不对的地方大家多指教啊. 一.添加控件IrisSkin2.dll. ...
- Qt 定时器Timer使用
From: http://dragoon666.blog.163.com/blog/static/107009194201092602326598/ 1.新建Gui工程,在主界面上添加一个标签labe ...
- AOP技术应用和研究--AOP简单应用
为了更好的理解AOP实践和体现AOP的优势.我们始终将OOP和AOP的比較贯穿到下文中.并在终于总结出AOP与OOP相比所拥有的长处,AOP的缺点以及AOP一般的使用场景. 1.1 问题空间到解空间的 ...
- 创建并调用 DLL(1)
//通过 DLL Wizard 建立: library TestDLL; uses SysUtils, Classes, Dialogs; {$R *.res} //建立过程 proced ...
- url中向后台传递中文乱码解决方法
方法一: 1.jsp中代码 var userNo = $('#prisoner_id').val(); userNo = encodeURI(userNo); allPrisone ...