题目描述

题解:

动态 点分治。

点分治可以帮助我们将树上的点分层,如果我们把这些点按生成顺序建树的话,我们会得到一棵点分树

点分树有一个特别好的性质,就是不管原来的树长什么样,建出来的点分树的深度都大约是$logn$。

而且若在点分树中a有一个儿子b,那么在原树中a的管辖子树(即找a作重心的子树)一定包含b的管辖子树。

(管辖子树这个名词是我瞎编的)

相当于把树分块,点分树中每一个点代表一块,

这样就是……树上线段树……了?

好像这就是动态点分。

本题要求区间修改,单点查询。

区间一个一个修改是不可能的,这辈子都不可能的

一定有骚操作,比如说挂几个标记。

比如每个点挂一棵线段树,然后记录管辖子树中和这个点距离为k的有多大收益。

比如这个图。

红点是高级重心,橙点是低级重心。

我们会发现,橙点能力过强时,他可以将部分范围传给高级中心。

但是有重叠部分啊。

所以我们还需要再开一棵线段树。

由于一个低级中心在点分树中只能有一个高级中心做父亲,所以我们可以在低级中心记录溢出了多少。

这道题就愉快的结束了。

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 100050
inline int rd()
{int f=1,c=0;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){c=10*c+ch-'0';ch=getchar();}return f*c;
}
int n,m,hed[N],cnt;
char c;
struct EG
{int to,nxt;
}e[2*N];
void ae(int f,int t)
{e[++cnt].to = t;e[cnt].nxt = hed[f];hed[f] = cnt;
}
int fa[N],son[N],dep[N],siz[N],top[N];
void dfs1(int u,int f)
{fa[u] = f;siz[u] = 1;dep[u] = dep[f]+1;for(int j=hed[u];j;j=e[j].nxt){int to = e[j].to;if(to==f)continue;dfs1(to,u);siz[u]+=siz[to];if(siz[to]>siz[son[u]])son[u] = to;}
}
void dfs2(int u,int tp)
{top[u] = tp;if(!son[u])return ;dfs2(son[u],tp);for(int j=hed[u];j;j=e[j].nxt){int to = e[j].to;if(to!=fa[u]&&to!=son[u])dfs2(to,to);}
}
int get_lca(int x,int y)
{while(top[x]!=top[y]){if(dep[top[x]]<dep[top[y]])swap(x,y);x = fa[top[x]];}return dep[x]<dep[y]?x:y;
}
int get_dis(int x,int y)
{return dep[x]+dep[y]-2*dep[get_lca(x,y)];
}
int rt,mrk[N],uf[N],sum,w[N],sz[N];
void get_rt(int u,int f)
{sz[u] = 1,w[u] = 0;for(int j=hed[u];j;j=e[j].nxt){int to = e[j].to;if(to==f||mrk[to])continue;get_rt(to,u);sz[u]+=sz[to];if(sz[to]>w[u])w[u]=sz[to];}w[u] = max(w[u],sum - sz[u]);if(w[u]<w[rt])rt = u;
}
void work(int u)
{mrk[u] = 1;int pre = sum;for(int j=hed[u];j;j=e[j].nxt){int to = e[j].to;if(mrk[to])continue;rt = 0,sum = (sz[to]>sz[u]?pre-sz[u]:sz[to]);get_rt(to,0);uf[rt] = u;work(rt);}
}
struct segtree
{int tot,rt[N],ls[150*N],rs[150*N],vl[150*N];void insert(int l,int r,int &u,int qx,int d){if(!u)u = ++tot;vl[u]+=d;if(l==r)return ;int mid = (l+r)>>1;if(qx<=mid)insert(l,mid,ls[u],qx,d);else insert(mid+1,r,rs[u],qx,d);}int query(int l,int r,int u,int ql,int qr){if(!u)return 0;if(l==ql&&r==qr)return vl[u];int mid = (l+r)>>1;if(qr<=mid)return query(l,mid,ls[u],ql,qr);else if(ql>mid)return query(mid+1,r,rs[u],ql,qr);else return query(l,mid,ls[u],ql,mid)+query(mid+1,r,rs[u],mid+1,qr);        }void push(int x,int s,int d){s = min(s,n);insert(0,n,rt[x],s,d);}int ask(int x,int s){return query(0,n,rt[x],s,n);}
}tr1,tr2;
int main()
{
//    freopen("1.in","r",stdin);n = rd(),m = rd();for(int f,t,i=1;i<n;i++){f = rd(),t = rd();ae(f,t),ae(t,f);}dfs1(1,0),dfs2(1,1);w[0] = 0x3f3f3f3f,rt = 0,sum = n;get_rt(1,0);work(rt);for(int x,d,w,i=1;i<=m;i++){c = getchar();while(c!='Q'&&c!='M')c = getchar();if(c=='Q'){x = rd();int ans = 0,p=x;while(p){ans+=tr1.ask(p,get_dis(p,x));if(uf[p])ans-=tr2.ask(p,get_dis(uf[p],x));p = uf[p];}printf("%d\n",ans);}else{x = rd(),d = rd(),w = rd();int p = x,las = 0;while(p){int now = d-get_dis(p,x);if(now<0){las = p,p = uf[p];continue;}tr1.push(p,now,w);if(las)tr2.push(las,now,w);las = p,p = uf[p];}}}return 0;
}

转载于:https://www.cnblogs.com/LiGuanlin1124/p/10190471.html

bzoj4372 烁烁的游戏相关推荐

  1. [bzoj4372]烁烁的游戏

    [bzoj4372]烁烁的游戏 动态点分,需要注意的是我们对于每个点要开两个数组,另外一个相当于一个容斥,即把他父亲上的减掉. 代码 #include<bits/stdc++.h> usi ...

  2. BZOJ4372: 烁烁的游戏

    BZOJ4372: 烁烁的游戏 https://lydsy.com/JudgeOnline/problem.php?id=4372 分析: 不是很难想的一道题,用树状数组维护点分树上每一层分治中心的点 ...

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

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

  4. BZOJ3730 震波+BZOJ4372 烁烁的游戏(动态点分治)

    震波 在一片土地上有N个城市,通过N-1条无向边互相连接,形成一棵树的结构,相邻两个城市的距离为1,其中第i个城市的价值为value[i]. 不幸的是,这片土地常常发生地震,并且随着时代的发展,城市的 ...

  5. BZOJ4372: 烁烁的游戏【动态点分治】

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

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

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

  7. bzoj4372. 烁烁的游戏【动态点分治】

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

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

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

  9. bzoj4372 烁烁的游戏 动态点分治+线段树

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

最新文章

  1. [英文面試]如何寫面試後的感謝信
  2. 百度bae mysql_微信公众号开发第二课 百度BAE搭建和数据库使用
  3. Omi应用md2site发布-markdown转网站利器
  4. APDPlat的系统启动和关闭流程剖析
  5. java注解编程_java 注解 基本原理 编程实现
  6. java与c应用,Java和C应用程序之间的IPC
  7. myabatis oracle 调用存储过程返回list结果集
  8. 使用numpy.tanh()打印矢量/矩阵元素的双曲正切值 使用Python的线性代数
  9. ROS on ARM--RK3066上本地编译ROS Groovy
  10. 负载均衡技术沙龙2期圆满结束(现场图文、PPT)
  11. 用ajax实现图片上传 帮你简单快速学会使用
  12. 网页游戏外挂的设计与编写:QQ摩天大楼【二】(登陆准备-信息处理方式)
  13. 木讷的程序员需要知道的事情 (六)
  14. linux shell中环境变量$PS1详解
  15. AE插件:能量激光描边光效特效Saber Mac
  16. JDBC连接Mysql并统计指定关键词在某一列中出现的次数
  17. 灰度巡线传感器_探索者D1系列教程十 巡线传感器
  18. c语言json 5c,什么是json的转义字符
  19. 使用Pelican在Github(国外线路访问)和Coding(国内线路访问)同步托管博客
  20. ConvNeXt网络详解

热门文章

  1. 2019最实用的8种精准微信引流方法教程
  2. 商业银行相关不良资产监管指标大全
  3. Win10安装Linux子系统教程
  4. 关于Kaggle入门,看这一篇就够了
  5. python——利用记忆曲线制作单词计划表
  6. matlab基础----复数表示
  7. CSS3 2D转换3D转换
  8. php小蛋白配方,卤蛋多种详细制作配方
  9. OSChina 周四乱弹 ——程序员要赚多少钱才能让妻子保持温柔和美丽
  10. 2019-nCoV肺炎疫情同程查询-完整提供 Demo 代码示例及数据专业且全面的 API 查询接口