您的位置:首页 > 其它

[BZOJ3730]震波(动态点分治)

2018-03-08 11:24 525 查看

 

3730: 震波

Time Limit: 15 Sec  Memory Limit: 256 MB
Submit: 2260  Solved: 470
[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

很久没有写过代码题了,被这道没什么难度的题目弄的心力交瘁。

很容易想到是动态点分治的题型,有可以看出需要数据结构维护,因为有影响半径的限制,又是求和,很容易想到线段树。这样由于树高的限制,每个点最多出现在log n棵线段树中,动态开点就好了。

实际上动态点分治不需要一上来就建点分树,遍历一遍求出每个点在点分树上的父节点就可以了,只有需要知道点分树的子节点在父节点在原树上的哪个子树内的时候才需要建图(将这个作为边权即可,参考BZOJ3924捉迷藏)。

这道题虽然只是几个模板拼在一起,但是我调了很久,说明对代码的熟练程度还有很大的欠缺。有很多错误,而且因为这道题既卡空间又卡时间,所以还需要各种卡常技巧,下面是一些我遇到的问题。

  • 不要建点分树,只需记录父节点。找中心的过程和普通点分治一样,rt和S作为全局变量而不是参数传入。
  • 注意看清题目,强制在线要记得异或。
  • 思路仍然是不断沿点分树向上爬,加上父节点的贡献减去自己的重复贡献。
  • 注意点分树上儿子到父亲的距离可能比儿子到自己的距离短。

还有一些卡常技巧(让常数优化成为一种习惯):

  • 快读和register最常用,但是寄存器容量有限要酌情选择。比较底层的函数的参数类型也可以设置为register int,也会有很大提升。
  • 线段树能避免update的尽量避免,可以标记永久化的就不要pushdown,比如单点修改区间求和就不需要update。
  • 增加一些循环终止条件。
  • 多维数组将少的维数提到前面,数组开2的次幂数加一并没有明显优化效果。
  • rmq求lca

想清楚之后就可以直接上代码了。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#define rg register int
#define rep(i,l,r) for (rg i=l; i<=r; i++)
#define For(i,x) for (int i=h[x],k; i; i=nxt[i])
typedef long long ll;
using namespace std;

const int N=100100,M=6000100,inf=1000000000;
int n,m,rt,S,op,x,y,lst,tot,nd,cnt,to[N<<1],nxt[N<<1],h
;
int sz
,fa
,vis
,st[20][N<<1],dep
;
int pos
,root
,root1
,lg[N<<1],f
,a
,sum[M],ls[M],rs[M];

template<typename T>inline void rd(T &x){
rg t; char ch;
for (t=0; !isdigit(ch=getchar()); t=(ch=='-'));
for (x=ch-'0'; isdigit(ch=getchar()); x=x*10+ch-'0');
if (t) x=-x;
}

void add(rg u,rg v){ to[++cnt]=v; nxt[cnt]=h[u]; h[u]=cnt; }

void find(rg x,rg fa){
sz[x]=1; f[x]=0;
For(i,x) if ((k=to[i])!=fa && !vis[k])
find(k,x),sz[x]+=sz[k],f[x]=max(f[x],sz[k]);
f[x]=max(f[x],S-sz[x]);
if (f[x]<f[rt]) rt=x;
}

void dfs(rg x,rg fa){
st[0][++tot]=dep[x]; pos[x]=tot;
For(i,x) if ((k=to[i])!=fa)
dep[k]=dep[x]+1,dfs(k,x),st[0][++tot]=dep[x];
}

void rmq(){
rep(j,1,18) rep(i,1,tot-(1<<j)+1)
st[j][i]=min(st[j-1][i],st[j-1][i+(1<<(j-1))]);
}

int get(rg l,rg r){
if (l>r) swap(l,r); rg t=lg[r-l+1];
return min(st[t][l],st[t][r-(1<<t)+1]);
}

int dis(rg u,rg v){ rg x=pos[u],y=pos[v]; return dep[u]+dep[v]-2*get(x,y); }

void mdf(rg &x,rg L,rg R,rg pos,rg k){
if (!x) x=++nd;
sum[x]+=k; if (L==R) return;
rg mid=(L+R)>>1;
if (pos<=mid) mdf(ls[x],L,mid,pos,k); else mdf(rs[x],mid+1,R,pos,k);
}

int que(rg x,rg L,rg R,rg pos){
if (!x) return 0;
if (L==R) return sum[x];
rg mid=(L+R)>>1;
if (pos<=mid) return que(ls[x],L,mid,pos);
else return sum[ls[x]]+que(rs[x],mid+1,R,pos);
}

void work(rg x,rg F,rg p){
mdf(root

,0,n,dis(x,p),a[x]); if (fa[p]) mdf(root1[p],0,n,dis(x,fa[p]),a[x]); For(i,x) if (!vis[k=to[i]] && k!=F) work(k,x,p); } void build(rg x){ vis[x]=1; work(x,fa[x],x); for (rg i=h[x],k; i; i=nxt[i]) if (!vis[k=to[i]]) f[rt=0]=inf,S=sz[k],find(k,x),fa[rt]=x,build(rt); } int getans(rg x,rg y){ rg res=que(root[x],0,n,y); rg D=0; for (rg i=x; fa[i]; i=fa[i]){ D=dis(x,fa[i]); if (D>y) continue; if (D-y>20) return x; res+=que(root[fa[i]],0,n,y-D)-que(root1[i],0,n,y-D); } return res; } void modify(rg x,rg y){ int t=y-a[x]; mdf(root[x],0,n,0,t); a[x]=y; for (int i=x; fa[i]; i=fa[i]){ mdf(root[fa[i]],0,n,dis(x,fa[i]),t); mdf(root1[i],0,n,dis(x,fa[i]),t); } } int main(){ freopen("bzoj3730.in","r",stdin); freopen("bzoj3730.out","w",stdout); rd(n); rd(m); rep(i,1,n) rd(a[i]); rep(i,1,n-1) rd(x),rd(y),add(x,y),add(y,x); dfs(1,0); rmq(); lg[1]=0; rep(i,2,tot) lg[i]=lg[i>>1]+1; f[rt=0]=inf; S=n; find(1,0); build(rt); rep(i,1,m){ rd(op); rd(x); rd(y); x^=lst; y^=lst; if (op==0) printf("%d\n",lst=getans(x,y)); else modify(x,y); } return 0; }

[p] 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: