题目描述

在一片土地上有N个城市,通过N-1条无向边互相连接,形成一棵树的结构,相邻两个城市的距离为1,其中第i个城市的价值为value[i]。
不幸的是,这片土地常常发生地震,并且随着时代的发展,城市的价值也往往会发生变动。
接下来你需要在线处理M次操作:
0 x k 表示发生了一次地震,震中城市为x,影响范围为k,所有与x距离不超过k的城市都将受到影响,该次地震造成的经济损失为所有受影响城市的价值和。
1 x y 表示第x个城市的价值变成了y。
为了体现程序的在线性,操作中的x、y、k都需要异或你程序上一次的输出来解密,如果之前没有输出,则默认上一次的输出为0。

输入

第一行包含两个正整数N和M。
第二行包含N个正整数,第i个数表示value[i]。
接下来N-1行,每行包含两个正整数u、v,表示u和v之间有一条无向边。
接下来M行,每行包含三个数,表示M次操作。

输出

包含若干行,对于每个询问输出一行一个正整数表示答案。

样例输入

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

样例输出

11100101

提示

1<=N,M<=100000
1<=u,v,x<=N
1<=value[i],y<=10000
0<=k<=N-1

我们考虑单次询问用点分治如何处理?假设查询点为x。

1、如果当前分治联通块中没有x,那么不用再分治统计了;

2、如果当前联通块中有x并且x不是分治中心,假设当前分治中心与x间的距离为d,我们需要找到与分治中心距离<=k-d的所有点的点权和。但这样统计有不合法的点,即与x在分治中心的同一棵子树中的点,所有我们还需要统计x所在的分治中心的那棵子树中与分治中心距离<=k-d的所有点权和,将这部分答案减掉即可。

3、如果x为当前分治中心,那么直接统计当前联通块中与x距离<=k的点的点权和即可。

其实第三种情况可以归为第二种情况中,那么我们就可以得出每个点需要维护的信息(其中k为任意距离,为了方便我们称以一个点为分治中心时能遍历到的点组成的联通块为这个点管辖的联通块):

1、以当前点为分治中心时联通块中与这个点距离<=k的点权和,这个用线段树维护每个距离的点权和即可。

2、以当前点在原树上的父节点为分治中心时,这个点在原树的子树中与这个点父节点距离<=k的点权和,这个同样用线段树维护,但是我们知道当前点在点分树上无法维护这个联通块的信息,所以这个联通块的信息由这个联通块的重心的那棵线段树来维护。也就变成了每个点维护点分树上这个点子树中所有点与这个点在点分树上的父节点距离<=k的点的点权和。

那么修改就很好办了,因为一个点的点权只被这个点在点分树上到根路径上所有点保存,只要暴力往根爬然后修改沿途节点线段树中信息即可。

对于查询,因为我们只需要知道管辖的联通块中包含查询点的点的信息即可,而这些点就是查询点在点分树上到根路径上的所有点,我们依旧暴力往根爬并统计沿途点的答案即可。

时间复杂度O(nlogn^2)

这个题很卡常,对于每个点要求出以它为分治中心时联通块中的最大深度作为这个点维护的线段树的上界,这样能减少递归层数。并且线段树数组要用结构体存,还要加读入优化……

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define mid ((l+r)>>1)
using namespace std;
inline char _read()
{
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int read()
{
int x=0,f=1;char ch=_read();
while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=_read();}
while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=_read();}
return x*f;
}
int n,m;
int tot;
int num;
int cnt;
int dfn;
int opt;
int x,y;
int ans;
int rot;
int res;
int mxp;
int f[100010];
int s[100010];
int d[100010];
int mn[100010];
int lg[200010];
int to[200010];
int mx[100010];
int dep[100010];
int val[100010];
int vis[100010];
int next[200010];
int head[100010];
int size[100010];
int root[100010];
int froot[100010];
int g[18][200010];
struct miku
{
int ls,rs,sum;
}tr[9000000];
inline void add(int x,int y)
{
next[++tot]=head[x],head[x]=tot,to[tot]=y;
}
void dfs(int x,int fa)
{
g[0][++dfn]=dep[x];
s[x]=dfn;
for(int i=head[x];i;i=next[i])
{
if(to[i]!=fa)
{
dep[to[i]]=dep[x]+1;
dfs(to[i],x);
g[0][++dfn]=dep[x];
}
}
}
inline void getroot(int x,int fa)
{
mx[x]=0;
size[x]=1;
for(int i=head[x];i;i=next[i])
{
if(!vis[to[i]]&&to[i]!=fa)
{
getroot(to[i],x);
size[x]+=size[to[i]];
mx[x]=max(mx[x],size[to[i]]);
}
}
mx[x]=max(mx[x],num-size[x]);
if(mx[x]<mx[rot])
{
rot=x;
}
}
void find_dep(int x,int fa)
{
d[x]=d[fa]+1;
mxp=max(mxp,d[x]);
for(int i=head[x];i;i=next[i])
{
if(!vis[to[i]]&&to[i]!=fa)
{
find_dep(to[i],x);
}
}
}
inline void partation(int x)
{
vis[x]=1;
mxp=0;
find_dep(x,0);
mn[x]=mxp;
for(int i=head[x];i;i=next[i])
{
if(!vis[to[i]])
{
num=size[to[i]];
rot=0;
getroot(to[i],0);
f[rot]=x;
partation(rot);
}
}
}
inline int lca(int x,int y)
{
x=s[x];
y=s[y];
if(x>y)
{
swap(x,y);
}
int len=lg[y-x+1];
return min(g[len][x],g[len][y-(1<<len)+1]);
}
inline int dis(int x,int y)
{
return dep[x]+dep[y]-(lca(x,y)<<1);
}
inline void insert(int &rt,int l,int r,int k,int x)
{
if(!rt)
{
rt=++cnt;
}
tr[rt].sum+=x;
if(l==r)
{
return ;
}
if(k<=mid)
{
insert(tr[rt].ls,l,mid,k,x);
}
else
{
insert(tr[rt].rs,mid+1,r,k,x);
}
}
inline int query(int rt,int l,int r,int k)
{
if(!rt)
{
return 0;
}
if(l==r)
{
return tr[rt].sum;
}
if(k<=mid)
{
return query(tr[rt].ls,l,mid,k);
}
else
{
return tr[tr[rt].ls].sum+query(tr[rt].rs,mid+1,r,k);
}
}
inline void change(int x,int val)
{
for(int i=x;i;i=f[i])
{
insert(root[i],0,mn[i],dis(x,i),val);
if(f[i])
{
insert(froot[i],0,mn[f[i]],dis(x,f[i]),val);
}
}
}
inline int query(int x,int k)
{
res=0;
for(int i=x;i;i=f[i])
{
if(dis(x,i)<=k)
{
res+=query(root[i],0,mn[i],k-dis(x,i));
}
if(f[i]&&dis(x,f[i])<=k)
{
res-=query(froot[i],0,mn[f[i]],k-dis(x,f[i]));
}
}
return res;
}
int main()
{
n=read();
m=read();
for(int i=1;i<=n;i++)
{
val[i]=read();
}
for(int i=1;i<n;i++)
{
x=read();
y=read();
add(x,y);
add(y,x);
}
dfs(1,0);
for(int i=2;i<=dfn;i++)
{
lg[i]=lg[i>>1]+1;
}
for(int j=1;(1<<j)<=dfn;j++)
{
for(int i=1;i+(1<<j)-1<=dfn;i++)
{
g[j][i]=min(g[j-1][i],g[j-1][i+(1<<(j-1))]);
}
}
mx[0]=1<<30;
num=n;
getroot(1,0);
partation(rot);
for(int now=1;now<=n;now++)
{
for(int i=now;i;i=f[i])
{
insert(root[i],0,mn[i],dis(now,i),val[now]);
if(f[i])
{
insert(froot[i],0,mn[f[i]],dis(now,f[i]),val[now]);
}
}
}
while(m--)
{
opt=read();
x=read()^ans;
y=read()^ans;
if(!opt)
{
printf("%d\n",ans=query(x,y));
}
else
{
change(x,y-val[x]);
val[x]=y;
}
}
}

BZOJ3730震波——动态点分治+线段树(点分树套线段树)的更多相关文章

  1. bzoj3730 震波 [动态点分治,树状数组]

    传送门 思路 如果没有强制在线的话可以离线之后CDQ分治随便搞. 有了强制在线之后--可能可以二维线段树?然而我不会算空间. 然后我们莫名其妙地想到了动态点分治,然后这题就差不多做完了. 点分树有一个 ...

  2. BZOJ3730 震波 | 动态点分治

    #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> # ...

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

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

  4. 【BZOJ-3730】震波 动态点分治 + 树状数组

    3730: 震波 Time Limit: 15 Sec  Memory Limit: 256 MBSubmit: 626  Solved: 149[Submit][Status][Discuss] D ...

  5. bzoj 3730: 震波 动态点分治_树链剖分_线段树

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

  6. 【BZOJ3730】震波 - 动态点分治

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

  7. [Codeforces757G]Can Bash Save the Day?——动态点分治(可持久化点分树)

    题目链接: Codeforces757G 题目大意:给出一棵n个点的树及一个1~n的排列pi,边有边权,有q次操作: 1 l r x 求 $\sum\limits_{i=l}^{r}dis(p_{i} ...

  8. BZOJ3435[Wc2014]紫荆花之恋——动态点分治(替罪羊式点分树套替罪羊树)

    题目描述 强强和萌萌是一对好朋友.有一天他们在外面闲逛,突然看到前方有一棵紫荆树.这已经是紫荆花飞舞的季节了,无数的花瓣以肉眼可见的速度从紫荆树上长了出来.仔细看看的话,这个大树实际上是一个带权树.每 ...

  9. bzoj 3730 震波 (动态点分治)

    大意: 给定n节点树, 每个节点有权值, 边权全为1. 给定m个操作: 操作1: (0,x,k) 表示询问到节点x距离不超过k的节点权值和 操作2: (1,x,y) 表示将节点x的权值修改为y 对于所 ...

随机推荐

  1. [程序员的业余生活]一周读完《高效能人士的七个习惯》Day1:这是不是一碗鸡汤?

    提出问题 今天突然想聊聊最近对职场的一些感悟. 这段时间,小端一直在思考一个问题:作为一个程序员,怎么才能成为团队的核心? 还记得刚入职场那几年,小端一直觉得,技术过硬,经验丰富,敢打敢拼,就是答案. ...

  2. RPM包制作过程(一)

    本机环境:centos7,64位 1. 首先安装工具,rpmbuild可能在rpmdevtools里已经包含 #yum install rpm-devel.x86_64 #yum install rp ...

  3. Python-初识算法-51

    # 什么叫算法# 计算的方法 : 人脑复杂 计算机简单 # 99 * 13 = 1287 = 13*100 - 13# 查找 : 找数据# 排序 :# 最短路径 # 我们学习的算法 都是过去时# 了解 ...

  4. Pytorch 初识

    文章目录 一个简单的回归网络的例子 再来一个例子 官方教程上图片识别的例子 import torch import torch.nn as nn import torch.nn.functional ...

  5. abaqus安装破解

    软件安装包 链接:http://pan.baidu.com/s/1pL4oxfX 密码:on1g 破解网页视频链接https://v.youku.com/v_show/id_XMTg4ODM5NjY5 ...

  6. CopyOnWriteArrayList源码分析

    基于jdk1.7源码 一.无锁容器 CopyOnWriteArrayList是JDK5中添加的新的容器,除此之外,还有CopyOnWriteArraySet.ConcurrentHahshMap和Co ...

  7. semantic-ui 分段

    分段:用于创建一组相关联的内容. 1.创建一个基础的分段 在class中加一个segment的class即可 <div class="ui segment"> < ...

  8. Codeforces Round #546 (Div. 2)

    http://codeforces.com/contest/1136 A #include <bits/stdc++.h> using namespace std; ; int N, K; ...

  9. 分布式文件系统FastDFS

    fastdfs_百度百科https://baike.baidu.com/item/fastdfs/5609710 用FastDFS一步步搭建文件管理系统 - bojiangzhou - 博客园http ...

  10. CLOUD SQL跟踪

    CLOUD会自动在后台执行一些sql语句,所以追踪起来比较麻烦,需要加入一些过滤条件. 比如关键的CLIENTPROCESSID,加入后 ,就能过滤是哪个客户度执行的数据. 过滤数据.