BZOJ3730 震波+BZOJ4372 烁烁的游戏(动态点分治)
震波
在一片土地上有N个城市,通过N-1条无向边互相连接,形成一棵树的结构,相邻两个城市的距离为1,其中第i个城市的价值为value[i]。
不幸的是,这片土地常常发生地震,并且随着时代的发展,城市的价值也往往会发生变动。
接下来你需要在线处理M次操作:
0 x k 表示发生了一次地震,震中城市为x,影响范围为k,所有与x距离不超过k的城市都将受到影响,该次地震造成的经济损失为所有受影响城市的价值和。
1 x y 表示第x个城市的价值变成了y。
为了体现程序的在线性,操作中的x、y、k都需要异或你程序上一次的输出来解密,如果之前没有输出,则默认上一次的输出为0。
Input
第一行包含两个正整数N和M。
第二行包含N个正整数,第i个数表示value[i]。
接下来N-1行,每行包含两个正整数u、v,表示u和v之间有一条无向边。
接下来M行,每行包含三个数,表示M次操作。
Output
包含若干行,对于每个询问输出一行一个正整数表示答案。
Sample Input
8 1 1 10 100 1000 10000 100000 1000000 10000000 1 2 1 3 2 4 2 5 3 6 3 7 3 8 0 3 1
Sample Output
11100101
Hint
1<=N,M<=100000
1<=u,v,x<=N
1<=value[i],y<=10000
0<=k<=N-1
题解
首先想到动态点分治+线段树
我们这时显然不能维护dfs序上的权值
我们可以对到当前点分中心的距离来开一个线段树
如果当前点分中心为u
那么线段树需要维护距离点u为 i 的所有点的权值之和
但是我们可能会算重,有可能点分中心的父亲会再一次计算某一些点的点权和
所有我们考虑如何去重
我们可以对点 u 再用一个线段树维护它的子树节点到它的点分树父亲的距离为 i 的点权和
在查询的时候减掉会被父亲计算的点的点权和即可
(强制在线,RE一般就是WA了,当然也有可能是真RE了)
代码:(查出来无数个sb错,还是一直RE,最后发现自己的动态开点线段树没有判等。。。)
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
inline int gi()
{char c;int num=0;while((c=getchar())<'0'||c>'9');while(c>='0'&&c<='9'){num=num*10+c-48;c=getchar();}return num;
}
#define N 100005
#define LOG 17
#define lc a[i].l,l,mid
#define rc a[i].r,mid+1,r
const int INF=0x3f3f3f3f;
int n,m;
int fir[N],to[2*N],nxt[2*N],cnt;
int val[N];
int tmpsiz[N],nrt,all;bool vis[N];
int dis[LOG][N],dfa[N],dep[N];
struct node{int l,r,x;}a[N*66];
int T1[N],T2[N],tot;
inline void adde(int a,int b)
{to[++cnt]=b;nxt[cnt]=fir[a];fir[a]=cnt;to[++cnt]=a;nxt[cnt]=fir[b];fir[b]=cnt;
}
void insert(int &i,int l,int r,int x,int k)
{if(!i)i=++tot;a[i].x+=k;if(l==r)return;int mid=(l+r)>>1;if(x<=mid)insert(lc,x,k);else insert(rc,x,k);
}
int query(int i,int l,int r,int qr)
{if(!i)return 0ll;if(l==r)return a[i].x;int mid=(l+r)>>1;if(qr<=mid)return query(lc,qr);else return a[a[i].l].x+query(rc,qr);
}
void findrt(int u,int ff)
{int mx=0;tmpsiz[u]=1;for(int v,p=fir[u];p;p=nxt[p]){if(!vis[v=to[p]]&&v!=ff){findrt(v,u);tmpsiz[u]+=tmpsiz[v];mx=max(mx,tmpsiz[v]);}}mx=max(mx,all-tmpsiz[u]);if(2*mx<=all)nrt=u;
}
inline int getrt(int u,int sz)
{nrt=-INF;all=sz;findrt(u,0);return nrt;
}
void pre(int u,int ff,int d,int rt)
{insert(T1[rt],0,n-1,dis[d][u],val[u]);if(dfa[rt])insert(T2[rt],0,n-1,dis[d-1][u],val[u]);//tmpsiz[u]=1;for(int v,p=fir[u];p;p=nxt[p]){if(!vis[v=to[p]]&&v!=ff){dis[d][v]=dis[d][u]+1;pre(v,u,d,rt);tmpsiz[u]+=tmpsiz[v];}}
}
void DFZ(int u,int d)
{vis[u]=1;dep[u]=d;dis[d][u]=0;pre(u,0,d,u);for(int v,p=fir[u];p;p=nxt[p]){if(!vis[v=to[p]]){dfa[v=getrt(v,tmpsiz[v])]=u;DFZ(v,d+1);}}
}
inline void modify(int u,int k)
{for(int t=u;t;t=dfa[t]){insert(T1[t],0,n-1,dis[dep[t]][u],k-val[u]);//if(dfa[t])insert(T2[t],0,n-1,dis[dep[t]-1][u],k-val[u]);//}val[u]=k;
}
inline int query(int u,int k)
{long long ans=0;for(int t=u;t;t=dfa[t]){if(dfa[t]&&dis[dep[t]-1][u]<=k) ans-=query(T2[t],0,n-1,k-dis[dep[t]-1][u]);//if(dis[dep[t]][u]<=k) ans+=query(T1[t],0,n-1,k-dis[dep[t]][u]);//}return int(ans);
}
int main()
{int i,op,u,v;int ans=0;n=gi();m=gi();for(i=1;i<=n;i++)val[i]=gi();for(i=1;i<n;i++){u=gi();v=gi();adde(u,v);}DFZ(getrt(1,n),0);for(i=1;i<=m;i++){op=gi();u=gi();v=gi();u^=ans;v^=ans;if(op)modify(u,v);else printf("%d\n",ans=query(u,v));}
}
烁烁的游戏
背景:烁烁很喜欢爬树,这吓坏了树上的皮皮鼠。
题意:
给定一颗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
7 6 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
2 3 6
Hint
数据范围:
n,m<=10^5,|w|<=10^4
注意:w不一定为正整数,因为烁烁可能把皮皮鼠吓傻了。
题解
这题就是上一道题的逆向版
上一道题:单点修改、前缀查询(好像可以用动态开点树状数组)
这一道题:前缀修改、单点查询
直接差分一下,变成单点修改、后缀查询(其实也可以单点修改两次,前缀查询,但是常数会大一些吧。。。。)
然后直接上动态点分治了,基本和上一题一样
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
inline int gi()
{char c;int num=0,flg=1;while((c=getchar())<'0'||c>'9')if(c=='-')flg=-1;while(c>='0'&&c<='9'){num=num*10+c-48;c=getchar();}return num*flg;
}
#define N 100005
#define LOG 17
const int INF=0x3f3f3f3f;
int n,m;
int fir[N],to[2*N],nxt[2*N],cnt;
void adde(int a,int b)
{to[++cnt]=b;nxt[cnt]=fir[a];fir[a]=cnt;to[++cnt]=a;nxt[cnt]=fir[b];fir[b]=cnt;
}
int tmpsiz[N],nrt,all;bool vis[N];
int dis[LOG][N],dfa[N],dep[N];
void findrt(int u,int ff)
{int mx=0;tmpsiz[u]=1;for(int v,p=fir[u];p;p=nxt[p]){if(!vis[v=to[p]]&&v!=ff){findrt(v,u);tmpsiz[u]+=tmpsiz[v];mx=max(mx,tmpsiz[v]);}}mx=max(mx,all-tmpsiz[u]);if(mx+mx<=all)nrt=u;
}
int getrt(int u,int sz)
{nrt=-INF;all=sz;findrt(u,0);return nrt;
}
#define lc a[i].l
#define rc a[i].r
struct node{int l,r,x;}a[N<<7];
int T1[N],T2[N],tot;
void insert(int &i,int l,int r,int x,int k)
{if(!i)i=++tot;a[i].x+=k;if(l==r)return;int mid=(l+r)>>1;if(x<=mid)insert(lc,l,mid,x,k);else insert(rc,mid+1,r,x,k);
}
int query(int i,int l,int r,int ql)
{if(!i)return 0;if(l==r)return a[i].x;int mid=(l+r)>>1;if(ql<=mid)return query(lc,l,mid,ql)+a[rc].x;else return query(rc,mid+1,r,ql);
}
void pre(int u,int ff,int d)
{tmpsiz[u]=1;for(int v,p=fir[u];p;p=nxt[p]){if(!vis[v=to[p]]&&v!=ff){dis[d][v]=dis[d][u]+1;pre(v,u,d);tmpsiz[u]+=tmpsiz[v];}}
}
void DFZ(int u,int d)
{vis[u]=1;dep[u]=d;pre(u,0,d);for(int v,p=fir[u];p;p=nxt[p]){if(!vis[v=to[p]]){dfa[v=getrt(v,tmpsiz[v])]=u;DFZ(v,d+1);}}
}
inline void modify(int u,int k,int s)
{for(int t=u;t;t=dfa[t]){if(dis[dep[t]][u]<=k) insert(T1[t],0,n,k-dis[dep[t]][u],s);//if(dfa[t]&&dis[dep[t]-1][u]<=k) insert(T2[t],0,n,k-dis[dep[t]-1][u],s);//}
}
inline int query(int u)
{long long ans=0;for(int t=u;t;t=dfa[t]){ans+=query(T1[t],0,n,dis[dep[t]][u]);//if(dfa[t]) ans-=query(T2[t],0,n,dis[dep[t]-1][u]);//}return int(ans);
}
char op[3];
int main()
{int i,u,v,s;n=gi();m=gi();for(i=1;i<n;i++){u=gi();v=gi();adde(u,v);}DFZ(getrt(1,n),0);for(i=1;i<=m;i++){scanf("%s",op);if(op[0]=='M'){u=gi();v=gi();s=gi();modify(u,v,s);}else printf("%d\n",query(gi()));}
}
BZOJ3730 震波+BZOJ4372 烁烁的游戏(动态点分治)相关推荐
- [BZOJ4372][烁烁的游戏][动态树分治+线段树+LCA]
[BZOJ4372][烁烁的游戏][动态树分治+线段树+LCA] 题目大意: 给定一颗nn个节点的树,边权均为11,初始每个点权值为00 . 其中操作QQ xx询问x点的点权,操作 MM xx dd ...
- bzoj4372 烁烁的游戏 动态点分治+线段树
Description 背景:烁烁很喜欢爬树,这吓坏了树上的皮皮鼠. 给定一颗n个节点的树,边权均为1,初始树上没有皮皮鼠. 烁烁他每次会跳到一个节点u,把周围与他距离不超过d的节点各吸引出w只皮皮鼠 ...
- BZOJ4372: 烁烁的游戏(动态点分治)
Description 背景:烁烁很喜欢爬树,这吓坏了树上的皮皮鼠. 题意: 给定一颗n个节点的树,边权均为1,初始树上没有皮皮鼠. 烁烁他每次会跳到一个节点u,把周围与他距离不超过d的节点各吸引出w ...
- 【BZOJ4372】烁烁的游戏 动态树分治+线段树
[BZOJ4372]烁烁的游戏 Description 背景:烁烁很喜欢爬树,这吓坏了树上的皮皮鼠. 题意: 给定一颗n个节点的树,边权均为1,初始树上没有皮皮鼠. 烁烁他每次会跳到一个节点u,把周围 ...
- 【bzoj4372】烁烁的游戏 动态点分治+线段树
题目描述 给一颗n个节点的树,边权均为1,初始点权均为0,m次操作: Q x:询问x的点权. M x d w:将树上与节点x距离不超过d的节点的点权均加上w. 输入 第一行两个正整数:n,m 接下来的 ...
- bzoj 4372: 烁烁的游戏 动态点分治_树链剖分_线段树
[Submit][Status][Discuss] Description 背景:烁烁很喜欢爬树,这吓坏了树上的皮皮鼠. 题意: 给定一颗n个节点的树,边权均为1,初始树上没有皮皮鼠. 烁烁他每次会跳 ...
- bzoj 4372 烁烁的游戏 —— 动态点分治+树状数组
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4372 本以为和 bzoj3730 一样,可以直接双倍经验了: 但要注意一下,树状数组不能查询 ...
- bzoj 4372 烁烁的游戏——动态点分治+树状数组
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4372 和 bzoj 3070 震波 是一个套路.注意区间修改的话,树状数组不能表示 dis ...
- [bzoj4372]烁烁的游戏
[bzoj4372]烁烁的游戏 动态点分,需要注意的是我们对于每个点要开两个数组,另外一个相当于一个容斥,即把他父亲上的减掉. 代码 #include<bits/stdc++.h> usi ...
最新文章
- 2009第二届C++技术大会即将在上海隆重召开
- Unity设置AppIcon方法
- 分享一下@Override标签背后的小秘密---记录java的思行合一
- swoole client php,Swoole Client
- stm32之ADC应用实例(单通道、多通道、基于DMA)
- windows7 安装IIS没有default web site 解决方法
- unity循环滚动列表_【unity游戏开发】LoopScrollRect组件
- 【系统架构设计师】2020-08-05
- Javascript-Switch
- 思维导图系列之Java多线程知识梳理
- c++ 内存泄露检测
- 如何构建一个县的shp图?R语言和Global mapper
- 每天吃多少才不会胖?食物和卡路里对照表
- 关于http响应200 OK的问题
- C#隐藏任务管理器中进程 支持win10 win8.1 win7
- 未来智能酒店里 智能管家将24小时待命
- 论文翻译 | TOOD:《TOOD: Task-aligned One-stage Object Detection》详细解读
- 图像处理之_ARToolKit自定义Marker
- 云计算技术,主要包括哪些关键技术?
- dos2unix 解决脚本执行过程中的莫名错误 “not found”