您的位置:首页 > 其它

bzoj 3730: 震波 (点分树+线段树)

2016-12-21 21:13 316 查看

3730: 震波

Time Limit: 15 Sec  Memory Limit: 256 MB
Submit: 501  Solved: 108

[Submit][Status][Discuss]

Description

在一片土地上有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

Source



最近敲这种一言不合代码就150+的点分树题已经麻木了QAQ

对于每个重心我们开两颗线段树(动态开):
一颗线段树中,对点分树中以u为根的子树中的节点v,我们以他距u的距离为下标,点权为值插入线段树
另一颗里,对点分治中以u为根的子树中的节点v,我们以他距u的父亲节点距离为下标,点权为值插入线段树
然后?你问我然后?
然后就修改暴力爬树高修改
然后就查询暴力爬树高查询,并消除上一层在当前层中重复的部分,统计答案就好

这种暴力爬树高,消除子树影响的方法其实很套路,建议先用点分树切掉bzoj3924或者看我这篇题解,然后搞这道题,具体过程依旧不细说,自己写的总是好,要攒人品。

代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<string>
#include<climits>
#include<queue>
#include<stack>
#include<map>
#include<set>
#define N 500100
#define M 1000200
#define lowbit(x) x&(-x)
using namespace std;
inline int read()
{
int x=0,f=1;char ch;
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int n,m,v
,ans;
int head
,pos;
struct edge{int to,next;}e[M];
inline void add(int a,int b)
{pos++;e[pos].to=b,e[pos].next=head[a],head[a]=pos;}

int dist
,ff
[20],dep
;
void dfs(int u,int fa)
{
dep[u]=dep[fa]+1;
ff[u][0]=fa;
for(int i=head[u];i;i=e[i].next)
{
int v=e[i].to;
if(v==fa)continue;
dist[v]=dist[u]+1;
dfs(v,u);
}
}
void make()
{
for(int k=1,j=2;j<=n;j<<=1,k++)
for(int i=1;i<=n;i++)
ff[i][k]=ff[ff[i][k-1]][k-1];
}
inline int lca(int x,int y)
{
if(dep[x]<dep[y])swap(x,y);
int tmp=dep[x]-dep[y];
for(int k=0,j=1;j<=tmp;j<<=1,k++)
if(tmp&j)x=ff[x][k];
while(x!=y)
{
int j=0;
while(ff[x][j]!=ff[y][j])j++;
if(j)j--;
x=ff[x][j],y=ff[y][j];
}return x;
}
inline int dis(int x,int y)
{
int lc=lca(x,y);
return dist[x]+dist[y]-2*dist[lc];
}

int root
[2],sz;
int s[N<<4],ls[N<<4],rs[N<<4];
inline void insert(int &u,int l,int r,int x,int val)
{
if(!u)u=++sz;s[u]+=val;
if(l==r)return;int mid=(l+r)>>1;
if(x<=mid)insert(ls[u],l,mid,x,val);
else insert(rs[u],mid+1,r,x,val);
}
inline int query(int u,int l,int r,int x,int y)
{
if(!u)return 0;
if(x<=l&&y>=r)return s[u];
int mid=(l+r)>>1;
if(y<=mid)return query(ls[u],l,mid,x,y);
else if(x>mid)return query(rs[u],mid+1,r,x,y);
else return query(ls[u],l,mid,x,mid)+query(rs[u],mid+1,r,mid+1,y);
}
int sum,f
,size
,rt;bool vis
;
void find_root(int u,int fa)
{
size[u]=1,f[u]=0;
for(int i=head[u];i;i=e[i].next)
{
int vv=e[i].to;
if(vv==fa||vis[vv])continue;
find_root(vv,u);
size[u]+=size[vv];
f[u]=max(f[u],size[vv]);
}f[u]=max(f[u],sum-size[u]);
if(f[u]<f[rt])rt=u;
}

int p
,d
;
void get_dep(int tr,int u,int fa)
{
insert(root[0],0,n,d[u],v[u]);
for(int i=head[u];i;i=e[i].next)
{
int v=e[i].to;
if(v==fa||vis[v])continue;
d[v]=d[u]+1;get_dep(tr,v,u);
}
}
void find_dep(int tr,int u,int fa)
{
insert(root[1],0,n,d[u],v[u]);
for(int i=head[u];i;i=e[i].next)
{
int v=e[i].to;
if(v==fa||vis[v])continue;
d[v]=d[u]+1;find_dep(tr,v,u);
}
}
void work(int u)
{
vis[u]=1;d[u]=0;get_dep(u,u,0);
for(int i=head[u];i;i=e[i].next)
{
int vv=e[i].to;
if(vis[vv])continue;
sum=size[vv],rt=0;
find_root(vv,0);p[rt]=u;
d[vv]=1;find_dep(rt,vv,u);
work(rt);
}
}

void updata(int u,int val)
{
int va=query(root[u][0],0,n,0,0);
int ct=val-va;
insert(root[u][0],0,n,0,ct);
for(int i=u;p[i];i=p[i])
{
int dt=dis(u,p[i]);
insert(root[p[i]][0],0,n,dt,ct);
insert(root[i][1],0,n,dt,ct);
}
}
int ask(int u,int k)
{
int j=k;
int ret=query(root[u][0],0,n,0,k);
for(int i=u;p[i];i=p[i])
{
int dt=dis(p[i],u);
ret+=query(root[p[i]][0],0,n,0,k-dt);
ret-=query(root[i][1],0,n,0,k-dt);
}return ret;
}
int main()
{
//	freopen("in.txt","r",stdin);
//	freopen("my.txt","w",stdout);
n=read(),m=read();
for(int i=1;i<=n;i++)
v[i]=read();
for(int i=1;i<n;i++)
{
int a=read(),b=read();
add(a,b);add(b,a);
}sum=f[0]=n;rt=0;
dfs(1,0);make();
find_root(1,0);
work(rt);
for(int i=1;i<=m;i++)
{
int f=read(),x=read(),y=read();
x^=ans,y^=ans;
if(f==0)printf("%d\n",ans=ask(x,y));
else  updata(x,y);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: