Description


背景:烁烁很喜欢爬树,这吓坏了树上的皮皮鼠。

给定一颗n个节点的树,边权均为1,初始树上没有皮皮鼠。
烁烁他每次会跳到一个节点u,把周围与他距离不超过d的节点各吸引出w只皮皮鼠。皮皮鼠会被烁烁吸引,所以会一直待在节点上不动。
烁烁很好奇,在当前时刻,节点u有多少个他的好朋友—皮皮鼠。
大意:
给一颗n个节点的树,边权均为1,初始点权均为0,m次操作:
Q x:询问x的点权。
M x d w:将树上与节点x距离不超过d的节点的点权均加上w。

n,m<=105,|w|<=104
注意:w不一定为正整数,因为烁烁可能把皮皮鼠吓傻了。

Solution


我终于会动态点分治辣

我们把点分治时下一层的分治中心作为此时分治中心的儿子,这样可以得到一棵新的树,我们称之为点分树
这棵新的树有许多优秀的性质,比如只有log层。于是一些跑不过的暴力就可以在点分树上套着数据结构跑了

在这题我们可以在每个节点x开一棵以 [x的点分树子树内到x距离] 作为下标的线段树,修改的时候就是把x到点分树的根路径上的所有线段树都改掉,查询同理。注意到直接这么做是会算重的,我们再开一棵以 [x的点分树子树内到fa[x]距离] 作为下标的线段树,这样修改的时候两棵都改,然后查询就能容斥去重了

线段树可以标记永久化,这样新建的节点少一些

需要注意的是点分树上两点距离是原树上两点的距离,且原树上的父子关系在点分树上不一定成立

跑得有点慢但是1A了

Code


#include <stdio.h>
#include <string.h>
#include <algorithm>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define drp(i,st,ed) for (int i=st;i>=ed;--i)const int INF=0x3f3f3f3f;
const int N=100005;struct treeNode {int l,r,tag;} t[N*289];
struct edge {int y,next;} e[N*2];int dep[N],acs[N][18],fa[N],size[N],mxSon[N];
int root1[N],root2[N],tot,rec,sum;
int ls[N],edCnt,n,m;bool del[N];int read() {int x=0,v=1; char ch=getchar();for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):(v),ch=getchar());for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());return x*v;
}void add_edge(int x,int y) {e[++edCnt]=(edge) {y,ls[x]}; ls[x]=edCnt;e[++edCnt]=(edge) {x,ls[y]}; ls[y]=edCnt;
}void dfs1(int now) {rep(i,1,17) acs[now][i]=acs[acs[now][i-1]][i-1];size[now]=1;for (int i=ls[now];i;i=e[i].next) {if (e[i].y==acs[now][0]) continue;acs[e[i].y][0]=now; dep[e[i].y]=dep[now]+1;dfs1(e[i].y); size[now]+=size[e[i].y];}
}void get_root(int now,int from) {size[now]=1; mxSon[now]=0;for (int i=ls[now];i;i=e[i].next) {if (e[i].y==from||del[e[i].y]) continue;get_root(e[i].y,now); size[now]+=size[e[i].y];mxSon[now]=std:: max(mxSon[now],size[e[i].y]);}mxSon[now]=std:: max(mxSon[now],sum-size[now]);if (mxSon[now]<mxSon[rec]) rec=now;
}void build(int now) {for (int i=ls[now];i;i=e[i].next) {if (del[e[i].y]) continue;rec=0; sum=size[e[i].y];get_root(e[i].y,now);fa[rec]=now; del[rec]=1;build(rec);}
}int get_lca(int x,int y) {if (dep[x]<dep[y]) std:: swap(x,y);drp(i,17,0) if (dep[acs[x][i]]>=dep[y]) x=acs[x][i];if (x==y) return x;drp(i,17,0) if (acs[x][i]!=acs[y][i]) x=acs[x][i],y=acs[y][i];return acs[x][0];
}int get_dis(int x,int y) {return dep[x]+dep[y]-dep[get_lca(x,y)]*2;
}void modify(int &now,int tl,int tr,int l,int r,int v) {if (r<l) return ;if (!now) now=++tot;if (tl>=l&&tr<=r) return (void) (t[now].tag+=v);int mid=(tl+tr)>>1;modify(t[now].l,tl,mid,l,std:: min(r,mid),v);modify(t[now].r,mid+1,tr,std:: max(mid+1,l),r,v);
}int query(int now,int tl,int tr,int x) {if (x<tl||x>tr) return 0;if (tl==tr) return t[now].tag;int mid=(tl+tr)>>1;int res=t[now].tag;res+=query(t[now].l,tl,mid,x);res+=query(t[now].r,mid+1,tr,x);return res;
}void change(int x,int d,int w) {int dis=0,st=x;modify(root1[x],0,n,0,d,w);while (fa[x]) {dis=get_dis(st,fa[x]);modify(root1[fa[x]],0,n,0,d-dis,w);modify(root2[x],0,n,0,d-dis,w);x=fa[x];}
}int ask(int x) {int res=query(root1[x],0,n,0);int dis=0,st=x;while (fa[x]) {dis=get_dis(st,fa[x]);res+=query(root1[fa[x]],0,n,dis);res-=query(root2[x],0,n,dis);x=fa[x];}return res;
}int main(void) {freopen("data.in","r",stdin);freopen("myp.out","w",stdout);n=read(),m=read(); mxSon[0]=INF;rep(i,2,n) add_edge(read(),read());dfs1(dep[1]=1);sum=n; rec=0; get_root(1,0);del[rec]=1; build(rec);for (char opt;m--;) {for (opt=getchar();opt!='M'&&opt!='Q';opt=getchar());int x=read();if (opt=='Q') printf("%d\n", ask(x));else {int d=read(),w=read();change(x,d,w);}}return 0;
}

bzoj4372 烁烁的游戏 动态点分治+线段树相关推荐

  1. 【bzoj4372】烁烁的游戏 动态点分治+线段树

    题目描述 给一颗n个节点的树,边权均为1,初始点权均为0,m次操作: Q x:询问x的点权. M x d w:将树上与节点x距离不超过d的节点的点权均加上w. 输入 第一行两个正整数:n,m 接下来的 ...

  2. bzoj 4372: 烁烁的游戏 动态点分治_树链剖分_线段树

    [Submit][Status][Discuss] Description 背景:烁烁很喜欢爬树,这吓坏了树上的皮皮鼠. 题意: 给定一颗n个节点的树,边权均为1,初始树上没有皮皮鼠. 烁烁他每次会跳 ...

  3. BZOJ4372: 烁烁的游戏(动态点分治)

    Description 背景:烁烁很喜欢爬树,这吓坏了树上的皮皮鼠. 题意: 给定一颗n个节点的树,边权均为1,初始树上没有皮皮鼠. 烁烁他每次会跳到一个节点u,把周围与他距离不超过d的节点各吸引出w ...

  4. [BZOJ4372][烁烁的游戏][动态树分治+线段树+LCA]

    [BZOJ4372][烁烁的游戏][动态树分治+线段树+LCA] 题目大意: 给定一颗nn个节点的树,边权均为11,初始每个点权值为00 . 其中操作QQ xx询问x点的点权,操作 MM xx dd ...

  5. BZOJ4372 烁烁的游戏(动态点分治+线段树)

    建出点分树,每个节点维护其作为点分树上lca对子树内点的贡献,线段树维护即可,同时另开一个线段树以减掉父亲重复的贡献. #include<iostream> #include<cst ...

  6. 震波——动态点分治+线段树

    题目 [题目描述] 在一片土地上有 $N$ 个城市,通过 $N-1$ 条无向边互相连接,形成一棵树的结构,相邻两个城市的距离为 $1$,其中第 $i$ 个城市的价值为 $value[i]$. 不幸的是 ...

  7. bzoj 4372 烁烁的游戏 —— 动态点分治+树状数组

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4372 本以为和 bzoj3730 一样,可以直接双倍经验了: 但要注意一下,树状数组不能查询 ...

  8. bzoj 4372 烁烁的游戏——动态点分治+树状数组

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4372 和 bzoj 3070 震波 是一个套路.注意区间修改的话,树状数组不能表示 dis ...

  9. 【BZOJ4372】烁烁的游戏 动态树分治+线段树

    [BZOJ4372]烁烁的游戏 Description 背景:烁烁很喜欢爬树,这吓坏了树上的皮皮鼠. 题意: 给定一颗n个节点的树,边权均为1,初始树上没有皮皮鼠. 烁烁他每次会跳到一个节点u,把周围 ...

最新文章

  1. 移动端丨-webkit-overflow-scrolling:touch属性导致页面卡住
  2. angularJs 之deferred
  3. openStack controller 管理网口TX数据量非常大 网络总是丢包
  4. (转)关于WSAEWOULDBLOCK
  5. Java 9中什么是私有的?
  6. 比较=、==、===
  7. 美国太空部队加入美国情报系统,以确保太空的安全
  8. explain分析sql效果
  9. 影响搜索引擎收录网站内容的四大原因分析
  10. [转载] python基础 - namedtuple和enum
  11. 【Android工具】更新简单好用IP端口扫描工具Fing Pro,网络设备查看工具,内网ip查询ip扫描工具,网络端口查询工具...
  12. 玻尔兹曼机(Boltzmann机)和深度置信网络基本概念
  13. Ionic3城市检索和滑动定位
  14. 仿真或极简,用户界面的美丽与哀愁
  15. html内联框架导航,html基本格式和内联框架
  16. 大数据风控在信贷行业的应用
  17. css什么是重绘重排,哪些操作会造成重绘重排
  18. ARCGIS对谷歌影像进行投影转换、影像拉伸纠偏处理及倾斜摄影纠偏
  19. STUFF函数介绍及使用场景
  20. 权限系统(vue+elementui)设计

热门文章

  1. 基于Quick-cocos2d-x 2.2.3 的动态更新实现
  2. 安全漏洞SCAP规范标准
  3. 纳米材料与技术类毕业论文文献有哪些?
  4. 那些前端用js手搓出来的算法与数据结构(一)链表篇
  5. 华为认证人工智能工程师 HCIA-AI V3.5(中文版) 发布通知
  6. 前端实现实时消息提醒消息通知
  7. VMware workstation批量创建虚拟机和自动化安装操作系统(二)
  8. 如何将微博全景图下载到手机发布至QQ
  9. Vue报错: [Vue warn]: Duplicate keys detected: ‘5‘. This may cause an update
  10. android室内定位传感器辅助pdr jar,基于Android的PDR和WiFi指纹融合室内定位技术研究...