题解-【集训队作业2018】Simple Tree

一道很无聊的题。出题人std写的是指令集暴力(

先考虑序列上怎么做,首先瞎归约一下可以发现只有根号做法。然后考虑分块,对于每个块内维护一个有序的数组,这样查询修改都是 (O(sqrt{n}log{n})) 的。然后考虑优化。首先是散块修改,可以使用归并排序做到 (O(sqrt{n}))。然后查询考虑直接维护一个指针和连续段,每次只会跳一个连续段,也可以做到 (O(sqrt{n}))。考虑上树。可以直接套用zx论文中树分块的做法,但是这样要特殊处理子树询问。

考虑树剖,直接做调整块大小是 (O(nsqrt{nlog n})) 的。然后有一个很神奇的优化(被lxl称作臭鱼烂虾分块),对每个重链分别做序列上的情况,块大小为重链长度开根。然后由于重链一定会翻倍,所以复杂度就对了。然后考虑子树查询,发现一定是一堆连续的完整重链,于是再搞个什么线段树就好了。复杂度 (O(nsqrt{n}+nlog^2{n}))

#include<bits/stdc++.h>
#define pii std::pair<int,int>
#define mp std::make_pair
#define F first
#define S second
const int maxn=200005;
template<typename T>
inline void read(T &x){
	T flag=1;
	char ch=getchar();
	for(;!isdigit(ch);ch=getchar())if(ch=='-')flag=-1;
	for(x=0;isdigit(ch);ch=getchar())x=x*10+ch-'0';
	x*=flag;
}
template<typename T>
inline void write(T x){
	if(x==0)return putchar('0'),void();
	int stkk[20],ttop=0;
	while(x){
		stkk[++ttop]=x%10;
		x/=10;
	}
	for(int i=ttop;i>=1;i--)putchar(stkk[i]+'0');
}
template<typename T>
inline void print(T x){
	if(x<0)putchar('-'),x=-x;
	write(x);
	putchar('
');
}
bool _;
int sum[maxn<<2];
inline void push_up(int p){
	sum[p]=sum[p<<1]+sum[p<<1|1];
}
void cc(int p,int l,int r,int ppos,int v){
	if(l==r)return sum[p]=v,void();
	int mid=(l+r)>>1;
	if(ppos<=mid)cc(p<<1,l,mid,ppos,v);
	else cc(p<<1|1,mid+1,r,ppos,v);
	push_up(p);
}
int qq(int p,int l,int r,int x,int y){
	if(l>y||r<x)return 0;
	if(x<=l&&r<=y)return sum[p];
	int mid=(l+r)>>1;
	return qq(p<<1,l,mid,x,y)+qq(p<<1|1,mid+1,r,x,y);
}
struct node{
	int pre,to;
}edge[maxn<<1];
int head[maxn],tttot=1;
int n,m,T,lastans,fa[maxn],dep[maxn],top[maxn],dfn[maxn],pos[maxn],Dfn,sz[maxn],son[maxn],lst[maxn];
int bel[maxn],L[maxn],R[maxn],tag[maxn],pp[maxn],ss[maxn],yy[maxn],tmp[maxn],B[maxn],len[maxn],tot;;
pii w[maxn],s1[maxn],s2[maxn];
bool __;
inline void add_edge(int u,int v){
	edge[++tttot]=node{head[u],v};
	head[u]=tttot;
}
void dfs1(int u){
	sz[u]=1;
	for(int i=head[u];i;i=edge[i].pre){
		int v=edge[i].to;
		if(v==fa[u])continue;
		fa[v]=u;
		dep[v]=dep[u]+1;
		dfs1(v);
		sz[u]+=sz[v];
		if(sz[v]>sz[son[u]])son[u]=v;
	}
}
void dfs2(int u,int chain){
	top[u]=chain;
	dfn[pos[u]=++Dfn]=u;
	if(son[u])dfs2(son[u],chain);
	for(int i=head[u];i;i=edge[i].pre){
		int v=edge[i].to;
		if(v==son[u]||v==fa[u])continue;
		dfs2(v,v);
	}
	lst[u]=Dfn;
	if(u==chain){
		for(int x=u;x;x=son[x])len[u]++;
		B[u]=std::max(1,int(sqrt(len[u]*0.6)));
		for(int i=pos[u],j=B[u];i<=pos[u]+len[u]-1;i++){
			if(j>=B[u])
				tot++,j=1,bel[i]=tot,L[tot]=i,R[tot]=i;
			else
				j++,bel[i]=tot,R[tot]=i;
		}
	}
}
inline void calc(int id){
	pp[id]=R[id]+1;
	for(int i=R[id];i>=L[id];i--)
		if(w[i].F>0)
			pp[id]=i;
	for(int i=L[id],j=i;i<=R[id];i=j+1){
		if(i==L[id]||w[i].F!=w[i-1].F){
			for(j=i+1;j<=R[id];j++)
				if(w[j].F!=w[i].F)
					break;
			j--;
			for(int k=i;k<=j;k++)
				ss[k]=i,yy[k]=j;
		}
	}
}
inline void build(int id){
	std::sort(w+L[id],w+R[id]+1);
	calc(id);
}
inline void modify(int id,int l,int r,int v){
	if(v==0&&tag[id]==0)return;
	int t1=0,t2=0;
	for(int i=L[id];i<=R[id];i++)
		w[i].F+=tag[id];
	tag[id]=0;
	for(int i=L[id];i<=R[id];i++){
		if(l<=w[i].S&&w[i].S<=r)
			w[i].F+=v,s2[++t2]=w[i];
		else s1[++t1]=w[i];
	}
	int r1=1,r2=1;
	for(int i=L[id];i<=R[id];i++)
		if(r1<=t1&&r2<=t2)
			w[i]=s1[r1]<s2[r2]?s1[r1++]:s2[r2++];
		else if(r1<=t1)
			w[i]=s1[r1++];
		else if(r2<=t2)
			w[i]=s2[r2++];
	calc(id);
}
inline int ask(int id,int l,int r){
	modify(id,-1,-1,0);
	int res=0;
	for(int i=L[id];i<=R[id];i++)
		if(l<=w[i].S&&w[i].S<=r)
			if(w[i].F>0)
				res++;
	return res;
}
inline int askh(int id){
	return R[id]-pp[id]+1;
}
inline void change(int id,int v){
	tag[id]+=v;
	if(v==1){
		if(pp[id]==L[id])return;
		if(tag[id]+w[pp[id]-1].F>0)
			pp[id]=ss[pp[id]-1];
	}else if(v==-1){
		if(pp[id]==R[id]+1)return;
		if(tag[id]+w[pp[id]].F<=0)
			pp[id]=yy[pp[id]]+1;
	}
}
inline void modify_s(int l,int r,int v){
	if(bel[l]==bel[r]){
		modify(bel[l],l,r,v);
	}else{
		modify(bel[l],l,R[bel[l]],v);
		modify(bel[r],L[bel[r]],r,v);
		for(int i=bel[l]+1;i<bel[r];i++)
			change(i,v);
	}
}
inline int qry(int l,int r){
	int res=0;
	if(bel[l]==bel[r]){
		res+=ask(bel[l],l,r);
	}else{
		res+=ask(bel[l],l,R[bel[l]]);
		res+=ask(bel[r],L[bel[r]],r);
		for(int i=bel[l]+1;i<bel[r];i++)
			res+=askh(i); 
	}
	return res;
}
int main(){
//	freopen("2.in","r",stdin);
//	freopen("2.out","w",stdout);
//	std::cout<<(((long long)&_-(long long)&__)>>20)<<"
";
	read(n);read(m);read(T);
	for(int i=1,u,v;i<n;i++){
		read(u);read(v);
		add_edge(u,v);add_edge(v,u);
	}
	for(int i=1;i<=n;i++)
		read(tmp[i]);
	dfs1(1);dfs2(1,1);
	for(int i=1;i<=n;i++)
		w[i]=mp(tmp[dfn[i]],i);
	for(int i=1;i<=tot;i++)build(i);
	for(int i=1;i<=n;i++){
		if(i==top[i]){
			int ccc=qry(pos[i],pos[i]+len[i]-1);
			cc(1,1,n,pos[i],ccc);
		}
	}
	while(m--){
		int op,x,y,r;
		read(op);read(x);x^=lastans;
		if(op==1){
			read(y);read(r);
			y^=lastans;
			int u=x,v=y;
			while(top[u]!=top[v]){
				if(dep[top[u]]<dep[top[v]])std::swap(u,v);
				modify_s(pos[top[u]],pos[u],r);
				int ccc=qry(pos[top[u]],pos[top[u]]+len[top[u]]-1);
				cc(1,1,n,pos[top[u]],ccc);
				u=fa[top[u]];
			}
			if(dep[u]>dep[v])std::swap(u,v);
			modify_s(pos[u],pos[v],r);
			int ccc=qry(pos[top[u]],pos[top[u]]+len[top[u]]-1);
			cc(1,1,n,pos[top[u]],ccc);
		}else if(op==2){
			read(y);
			y^=lastans;
			int u=x,v=y,ans=0;
			while(top[u]!=top[v]){
				if(dep[top[u]]<dep[top[v]])std::swap(u,v);
				ans+=qry(pos[top[u]],pos[u]);
				u=fa[top[u]];
			}
			if(dep[u]>dep[v])std::swap(u,v);
			ans+=qry(pos[u],pos[v]);
			print(ans);
			if(T==1)lastans=ans;
		}else{
			int ans=qry(pos[x],pos[top[x]]+len[top[x]]-1)+qq(1,1,n,pos[top[x]]+len[top[x]],lst[x]);
			print(ans); 
			if(T==1)lastans=ans;
		}
	}
	return 0;
}
原文地址:https://www.cnblogs.com/zcr-blog/p/15496886.html