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

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
#define N 100010
char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;}
int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
int read()
{
int x=0,f=1;char c=getchar();
while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
return x*f;
}
int n,m,p[N],size[N],deep[N],fa[N][19],t;
bool flag[N];
struct data{int to,nxt;
}edge[N<<1];
void addedge(int x,int y){t++;edge[t].to=y,edge[t].nxt=p[x],p[x]=t;}
void dfs(int k)
{
for (int i=p[k];i;i=edge[i].nxt)
if (edge[i].to!=fa[k][0])
{
fa[edge[i].to][0]=k;
deep[edge[i].to]=deep[k]+1;
dfs(edge[i].to);
}
}
int lca(int x,int y)
{
if (deep[x]<deep[y]) swap(x,y);
for (int j=18;~j;j--) if (deep[fa[x][j]]>=deep[y]) x=fa[x][j];
if (x==y) return x;
for (int j=18;~j;j--) if (fa[x][j]!=fa[y][j]) x=fa[x][j],y=fa[y][j];
return fa[x][0];
}
int dis(int x,int y){return deep[x]+deep[y]-(deep[lca(x,y)]<<1);}
namespace newtree
{
int rt,cnt[2],root[2][N],fa[N];
struct data{int l,r,x;}tree[2][N<<7];
void addedge(int x,int y){fa[y]=x;}
void add(int &k,int l,int r,int p,int x,int op)
{
if (!k) k=++cnt[op];
tree[op][k].x+=x;
if (l==r) return;
int mid=l+r>>1;
if (p<=mid) add(tree[op][k].l,l,mid,p,x,op);
else add(tree[op][k].r,mid+1,r,p,x,op);
}
int sum(int k,int l,int r,int x,int op)
{
if (!k) return 0;
if (l==r) return tree[op][k].x;
int mid=l+r>>1;
if (x<=mid) return sum(tree[op][k].l,l,mid,x,op);
else return tree[op][tree[op][k].l].x+sum(tree[op][k].r,mid+1,r,x,op);
}
void modify(int x,int d,int w)
{
add(root[0][x],0,n,0,w,0),add(root[0][x],0,n,d+1,-w,0);
int i=x;
while (i!=rt)
{
int D=dis(x,fa[i]);
if (D<=d)
add(root[0][fa[i]],0,n,0,w,0),add(root[0][fa[i]],0,n,d-D+1,-w,0),
add(root[1][i],0,n,0,-w,1),add(root[1][i],0,n,d-D+1,w,1);
i=fa[i];
}
}
int query(int x)
{
int ans=0,i=x;
while (i) ans+=sum(root[0][i],0,n,dis(x,i),0),ans+=sum(root[1][i],0,n,dis(x,fa[i]),1),i=fa[i];
return ans;
}
}
void make(int k,int from)
{
size[k]=1;
for (int i=p[k];i;i=edge[i].nxt)
if (!flag[edge[i].to]&&edge[i].to!=from)
{
make(edge[i].to,k);
size[k]+=size[edge[i].to];
}
}
int findroot(int k,int from,int s)
{
int mx=0;
for (int i=p[k];i;i=edge[i].nxt)
if (!flag[edge[i].to]&&edge[i].to!=from&&size[edge[i].to]>size[mx]) mx=edge[i].to;
if ((size[mx]<<1)>s) return findroot(mx,k,s);
else return k;
}
int build(int k)
{
make(k,k);
flag[k=findroot(k,k,size[k])]=1;
for (int i=p[k];i;i=edge[i].nxt)
if (!flag[edge[i].to]) newtree::addedge(k,build(edge[i].to));
return k;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("bzoj4372.in","r",stdin);
freopen("bzoj4372.out","w",stdout);
const char LL[]="%I64d\n";
#else
const char LL[]="%lld\n";
#endif
n=read(),m=read();
for (int i=1;i<n;i++)
{
int x=read(),y=read();
addedge(x,y),addedge(y,x);
}
fa[1][0]=1;dfs(1);
for (int j=1;j<19;j++)
for (int i=1;i<=n;i++)
fa[i][j]=fa[fa[i][j-1]][j-1];
newtree::rt=build(1);
while (m--)
{
char c=getc();
if (c=='M')
{
int x=read(),d=read(),w=read();
newtree::modify(x,d,w);
}
else printf("%d\n",newtree::query(read()));
}
return 0;
}

  

BZOJ4372 烁烁的游戏(动态点分治+线段树)的更多相关文章

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

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

  2. [bzoj4372] 烁烁的游戏 [动态点分治+线段树+容斥原理]

    题面 传送门 思路 观察一下题目,要求的是修改"距离点$u$的距离一定的点权值",那这个就不能用传统的dfs序类算法+线段树维护,因为涉及到向父亲回溯的问题 看到和树上距离相关的东 ...

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

    和[BZOJ3730]震波几乎一样,每个点建两棵线段树分别代表它的管辖范围内以它为LCA的路径的贡献和它对父亲的贡献. 注意点分树上的点的距离在原树上不单调,所以不能有若距离超出限制就break之类的 ...

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

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

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

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

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

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

  7. 【loj6145】「2017 山东三轮集训 Day7」Easy 动态点分治+线段树

    题目描述 给你一棵 $n$ 个点的树,边有边权.$m$ 次询问,每次给出 $l$ .$r$ .$x$ ,求 $\text{Min}_{i=l}^r\text{dis}(i,x)$ . $n,m\le ...

  8. 【bzoj3730】震波 动态点分治+线段树

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

  9. 2019ICPC上海网络赛 A Lightning Routing I 点分树(动态点分治)+线段树

    题意 给一颗带边权的树,有两种操作 \(C~e_i~w_i\),将第\(e_i\)条边的边权改为\(w_i\). \(Q~v_i\),询问距\(v_i\)点最远的点的距离. 分析 官方题解做法:动态维 ...

随机推荐

  1. linux 开机进入initramfs无法开机

    4/4 用fsck命令开始检查.修复(fsck是个很好用了磁盘检测修复命令)输入:fsck -t ext4 /dev/sda1 (-t是指定文件系统类型:现在的多半是ext3和ext4,不知道,你就一 ...

  2. 重装系统之win10不能进入bios界面

    原因 自Win10发布以来,新出厂的预装Win10的电脑都默认在UEFI模式下启动操作系统.UEFI启动是一种新的主板引导项,正被看做是有近20多年历史的BIOS 的继任者.顾名思义,快速启动是可以提 ...

  3. vue2.0中使用pug(jade)

    第一部分:pug(jade)模板引擎 pug,原名jade,是流行的HTML模板引擎,它是HAML在JavaScript上的实现,最大的特色是使用缩进排列替代成对标签. 它简化了HTML的成对标签的写 ...

  4. Codeforces 999D Equalize the Remainders (set使用)

    题目连接:Equalize the Remainders 题意:n个数字,对m取余有m种情况,使得每种情况的个数都为n/m个(保证n%m=0),最少需要操作多少次? 每次操作可以把某个数字+1.输出最 ...

  5. 程序员从技术开发到项目管理PM--思维转变

    对以往所做项目的经验做下总结,作为项目经理首先要对项目负责,思维要做下转变,要从项目全局角度考虑问题:     从个人成就到团队成就. 无论是做管理还是做技术,成就导向意识是优秀员工的基本素质.只有具 ...

  6. Linux ugo 权限

    Linux 系统中文件的 ugo 权限是 Linux 进行权限管理的基本方式.本文将介绍 ugo 权限的基本概念.说明:本文的演示环境为 ubuntu 16.04. 文件的所有者和组 Linux 文件 ...

  7. django通用权限控制框架

    在web项目中根据不同的用户肯定会限制其不同的权限,利用以下模块可以满足日常几乎所有的权限控制 permission_hook.py  # 自定义权限控制,必须返回True/false  ,True表 ...

  8. Linux下开源邮件系统Postfix+Extmail+Extman环境部署记录

    一.基础知识梳理MUA (Mail User Agent) MUA 既是"邮件使用者代理人",因为除非你可以直接利用类似 telnet 之类的软件登入邮件主机来主动发出信件,否则您 ...

  9. main函数是必须的吗

    研究实验4 研究过程: 问题引出:C语言编程非得用主函数main吗,不用是否可以? 对此问题进行研究,用tc.exe书写代码如下: 图1  没有main函数的c程序 对其进行编译,链接发现,编译阶段可 ...

  10. VS2013安装和单元测试

    1. VC2013安装过程及使用感受 刚上大一的时候老师推荐我们用VC++6.0.当时也就听了老师的话用VC++6.0编程了一段时间.后来上了大二买了电脑VC++6.0支持不了WIN8.1所以我就开始 ...