BZOJ 3730 震波

题目链接:震波

  这道题有种紫荆花之恋的既视感→_→

  于是我果断写了点分+treap,结果这道题卡常数,\(treap\)被生生卡掉了……看来我以前低估了\(treap\)的常数……

  于是我一气之下把\(treap\)改成了线段树,然后发现空间似乎多了一个\(\log\)……接着仔细想了想,发现由于每棵子树有用的下标是连续的一段,那么我只需要控制一下每棵线段树维护的区间,那么每棵线段树所用空间就是\(O(size)\)的了,于是总空间就变成了\(O(n\log n)\)……

  UPD:好像不需要这样,空间直接就是\(O(n\log n)\)的……因为只有一段区间内的下标是有用的,所以线段树只会开\(O(size+\log n)\)的空间……(捂脸

  还是讲讲做法吧。首先,两个点之间的路径必然会经过他们在点分树上的$lca$(这不是废话么)。我们把点分的结构维护下来,对每个节点\(u\)开一棵线段树,维护它的子树中到\(u\)距离为\(x\)的所有点的点权和。然后查询时一路往上跳,在线段树中查询即可。

  但是这样显然是会算重的。于是我没对每个节点再维护一棵线段树,维护每个点到$father_u$(\(u\)在点分树上的父亲)的距离,跳的时候加加减减就做完了。当然这里省略了很多细节……留给写这道题的人自己去发现。

  还有没有异或上次的\(ans\)导致无限RE……不开心……

  下面贴代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
#define maxn 100010
#define MAXN maxn*50

using namespace std;
typedef long long llg;

int n,m,a[maxn],fa[maxn],siz[maxn],dx[maxn];
int head[maxn],next[maxn<<1],to[maxn<<1],tt,dep[maxn];
int dis[maxn][30],d[maxn],ld,du[maxn],co[maxn][2];
int val[MAXN],zhi[MAXN],sumv[MAXN],ans;
int s[MAXN][2],rt[maxn][2],R,Z,_sum;
bool vis[maxn];

int getint(){
	int w=0;bool q=0;
	char c=getchar();
	while((c>'9'||c<'0')&&c!='-') c=getchar();
	if(c=='-') c=getchar(),q=1;
	while(c>='0'&&c<='9') w=w*10+c-'0',c=getchar();
	return q?-w:w;
}

void link(int x,int y){
	to[++tt]=y;next[tt]=head[x];head[x]=tt;
	to[++tt]=x;next[tt]=head[y];head[y]=tt;
}

inline void add(int &x,int l,int r){
	if(!x) x=++tt; int u=x;
	sumv[u]+=Z; int mid;
	while(l!=r){
		mid=(l+r)>>1;
		if(R<=mid) u=(s[u][0]?s[u][0]:s[u][0]=++tt),r=mid;
		else u=(s[u][1]?s[u][1]:s[u][1]=++tt),l=mid+1;
		sumv[u]+=Z;
	}
}

inline void query(int u,int l,int r){
	if(R<l) return;
	while(l!=r){
		if(!u || r<=R) break; int mid=(l+r)>>1;
		if(R<=mid) u=s[u][0],r=mid;
		else _sum+=sumv[s[u][0]],l=mid+1,u=s[u][1];
	}
	_sum+=sumv[u];
}

void dfs2(int u,int now){
	vis[u]=1; siz[u]=1; dx[u]=0; d[++ld]=u; du[ld]=now;
	for(int i=head[u],v;v=to[i],i;i=next[i])
		if(!vis[v]) dfs2(v,now+1),siz[u]+=siz[v],dx[u]=max(dx[u],siz[v]);
	vis[u]=0;
}

void dfs1(int x,int ff){
	ld=0; dfs2(x,0); int k=0;
	for(int i=1,u;u=d[i],i<=ld;i++){
		dx[u]=max(dx[u],siz[x]-siz[u]);
		if(dx[u]<dx[k]) k=u;
	}
	ld=0; dfs2(k,0); vis[k]=1; fa[k]=ff;
	dep[k]=dep[ff]+1;
	for(int i=1,u;u=d[i],i<=ld;i++){
		co[k][0]=max(co[k][0],du[i]);
		co[k][1]=max(co[k][1],dis[u][dep[ff]]);
	}
	for(int i=1,u;u=d[i],i<=ld;i++){
		Z=a[u]; R=dis[u][dep[k]]=du[i],add(rt[k][0],0,co[k][0]);
		if(ff) R=dis[u][dep[ff]],add(rt[k][1],1,co[k][1]);
	}
	for(int i=head[k],v;v=to[i],i;i=next[i])
		if(!vis[v]) dfs1(v,k);
}

int main(){
	File("a");
	n=getint(); m=getint(); dx[0]=n+1;
	for(int i=1;i<=n;i++) a[i]=getint();
	for(int i=2;i<=n;i++) link(getint(),getint());
	tt=0; dfs1(1,0);
	while(m--){
		int ty=getint(),x=getint()^ans,y=getint()^ans;
		if(!ty) ans=0;
		for(int u=x,d=dep[x];u;u=fa[u],d--){
			if(!ty) R=y-dis[x][d],_sum=0,query(rt[u][0],0,co[u][0]),ans+=_sum;
			else R=dis[x][dep[u]],Z=y-a[x],add(rt[u][0],0,co[u][0]);
			if(fa[u])
				if(!ty) R=y-dis[x][d-1],_sum=0,query(rt[u][1],1,co[u][1]),ans-=_sum;
				else R=dis[x][dep[fa[u]]],Z=y-a[x],add(rt[u][1],1,co[u][1]);
		}
		if(ty) a[x]=y;
		else printf("%d\n",ans);
	}
	return 0;
}

   老年选手BZOJ 终于233题辣!(现在才刷了这么点题的我真是一条咸鱼)

posted @ 2017-02-04 23:06  lcf2000  阅读(234)  评论(1编辑  收藏  举报