BZOJ3159 决战

题意


分析

树剖套平衡树。

难点在于路径翻转,其他的线段树都可以解决。

考虑套Splay,随便想想这操作就是将\(O(\log n)\)的区间翻转,翻转一个耗时\(O(\log n)\),所以总复杂度是\(O(\log^2 n)\)的。

然而你仔细想想貌似没有那么简单,主要是代码很烦,这么那么对应的。

注意到这题的性质,X国司令的操作的起点和终点的选取,都十分的睿智,这为我们简化代码提供了条件。若以r为根来树剖,那么这些区间端点的dfn是有序的,因为祖先的dfn小于后代的dfn。

然后就可以方便的将带翻转的区间提取出来,合并成一棵树,翻转一下,再拆分回去,最后合并起来即为新树。

时间复杂度\(O(n \log^2 n)\)

打代码的时候我努力追求码风,然后每个细节都考虑的非常清楚,交上去竟然一遍AC了。自我感觉良好。

代码

我用函数式Treap实现了Splay。(话说Splay现在除了在LCT里面有用之外就是个废物)

我没有卡常,我也不喜欢卡常。

#include<bits/stdc++.h>
#define rg register
#define il inline
#define co const
template<class T>il T read() {
	rg T data=0;
	rg int w=1;
	rg char ch=getchar();
	while(!isdigit(ch)) {
		if(ch=='-')
			w=-1;
		ch=getchar();
	}
	while(isdigit(ch)) {
		data=data*10+ch-'0';
		ch=getchar();
	}
	return data*w;
}
template<class T>il T read(rg T&x) {
	return x=read<T>();
}
typedef long long ll;

co int N=5e4+7;

int root,tot;
namespace T {
	int ch[N][2],siz[N],pri[N];
	ll val[N],sum[N],max[N],min[N],tag[N];
	bool rev[N];

	int newnode(ll v) {
		int x=++tot;
		ch[x][0]=ch[x][1]=0,siz[x]=1,pri[x]=rand();
		val[x]=sum[x]=v;
		max[x]=min[x]=v;
		tag[x]=rev[x]=0;
		return x;
	}

	void pushup(int x) {
		siz[x]=siz[ch[x][0]]+1+siz[ch[x][1]];
		sum[x]=sum[ch[x][0]]+val[x]+sum[ch[x][1]];
		max[x]=std::max(max[ch[x][0]],std::max(val[x],max[ch[x][1]]));
		min[x]=std::min(min[ch[x][0]],std::min(val[x],min[ch[x][1]]));
	}

	void rever(int x) {
		std::swap(ch[x][0],ch[x][1]);
		rev[x]^=1;
	}

	void add(int x,ll v) {
		val[x]+=v;
		sum[x]+=siz[x]*v;
		max[x]+=v;
		min[x]+=v;
		tag[x]+=v;
	}

	void pushdown(int x) {
		if(rev[x]) {
			if(ch[x][0])
				rever(ch[x][0]);
			if(ch[x][1])
				rever(ch[x][1]);
			rev[x]=0;
		}
		if(tag[x]) {
			if(ch[x][0])
				add(ch[x][0],tag[x]);
			if(ch[x][1])
				add(ch[x][1],tag[x]);
			tag[x]=0;
		}
	}

	void split(int x,int k,int&l,int&r) {
		if(!x) {
			l=r=0;
			return;
		}
		if(siz[ch[x][0]]+1<=k) {
			l=x;
			pushdown(l);
			split(ch[l][1],k-siz[ch[x][0]]-1,ch[l][1],r);
			pushup(l);
		} else {
			r=x;
			pushdown(r);
			split(ch[r][0],k,l,ch[r][0]);
			pushup(r);
		}
	}

	int merge(int x,int y) {
		if(!x||!y)
			return x+y;
		if(pri[x]>pri[y]) {
			pushdown(x);
			ch[x][1]=merge(ch[x][1],y);
			pushup(x);
			return x;
		} else {
			pushdown(y);
			ch[y][0]=merge(x,ch[y][0]);
			pushup(y);
			return y;
		}
	}

	void Increase(int&t,int l,int r,ll v) {
		int x,y,z;
		split(t,l-1,x,y);
		split(y,r-l+1,y,z);
		if(y)
			add(y,v);
		t=merge(x,merge(y,z));
	}

	ll Sum(int&t,int l,int r) {
		int x,y,z;
		split(t,l-1,x,y);
		split(y,r-l+1,y,z);
		ll res=sum[y];
		t=merge(x,merge(y,z));
		return res;
	}

	ll Major(int&t,int l,int r) {
		int x,y,z;
		split(t,l-1,x,y);
		split(y,r-l+1,y,z);
		ll res=max[y];
		t=merge(x,merge(y,z));
		return res;
	}

	ll Minor(int&t,int l,int r) {
		int x,y,z;
		split(t,l-1,x,y);
		split(y,r-l+1,y,z);
		ll res=min[y];
		t=merge(x,merge(y,z));
		return res;
	}

	typedef std::pair<int,int> pii;
	typedef std::vector<pii> path;
	typedef std::vector<int> subtree;

	void Invert(int&t,path p) {
		subtree s;
		s.push_back(t);
		for(int i=p.size()-1; i>=0; --i) {
			int x=s.back(),l,r;
			s.pop_back();
			split(x,p[i].second,x,r);
			split(x,p[i].first-1,l,x);
			s.push_back(r);
			s.push_back(x);
			s.push_back(l);
		}
		reverse(s.begin(),s.end());
		for(int i=1; i<p.size(); ++i)
			s[1]=merge(s[1],s[2*i+1]);
		rever(s[1]);
		for(int i=p.size()-1; i; --i)
			split(s[1],siz[s[1]]-(p[i].second-p[i].first+1),s[1],s[2*i+1]);
		for(int i=1; i<s.size(); ++i)
			s[0]=merge(s[0],s[i]);
		t=s[0];
	}
}

int n,m,r;
std::vector<int>g[N];
int dep[N],siz[N],fa[N],son[N];

void dfs1(int x,int fa) {
	dep[x]=dep[fa]+1,siz[x]=1,::fa[x]=fa;
	for(int i=0; i<g[x].size(); ++i) {
		int y=g[x][i];
		if(y==fa)
			continue;
		dfs1(y,x);
		siz[x]+=siz[y];
		if(siz[y]>siz[son[x]])
			son[x]=y;
	}
}

int dfn[N],id,top[N];

void dfs2(int x,int top) {
	dfn[x]=++id,::top[x]=top;
	if(!son[x])
		return;
	dfs2(son[x],top);
	for(int i=0; i<g[x].size(); ++i) {
		int y=g[x][i];
		if(y==fa[x]||y==son[x])
			continue;
		dfs2(y,y);
	}
}

void Increase(int x,int y,ll v) {
	while(top[x]!=top[y]) {
		if(dep[top[x]]<dep[top[y]])
			std::swap(x,y);
		T::Increase(root,dfn[top[x]],dfn[x],v);
		x=fa[top[x]];
	}
	if(dep[x]>dep[y])
		std::swap(x,y);
	T::Increase(root,dfn[x],dfn[y],v);
}

ll Sum(int x,int y) {
	ll res=0;
	while(top[x]!=top[y]) {
		if(dep[top[x]]<dep[top[y]])
			std::swap(x,y);
		res+=T::Sum(root,dfn[top[x]],dfn[x]);
		x=fa[top[x]];
	}
	if(dep[x]>dep[y])
		std::swap(x,y);
	res+=T::Sum(root,dfn[x],dfn[y]);
	return res;
}

ll Major(int x,int y) {
	ll res=0;
	while(top[x]!=top[y]) {
		if(dep[top[x]]<dep[top[y]])
			std::swap(x,y);
		res=std::max(res,T::Major(root,dfn[top[x]],dfn[x]));
		x=fa[top[x]];
	}
	if(dep[x]>dep[y])
		std::swap(x,y);
	res=std::max(res,T::Major(root,dfn[x],dfn[y]));
	return res;
}

ll Minor(int x,int y) {
	ll res=5e7;
	while(top[x]!=top[y]) {
		if(dep[top[x]]<dep[top[y]])
			std::swap(x,y);
		res=std::min(res,T::Minor(root,dfn[top[x]],dfn[x]));
		x=fa[top[x]];
	}
	if(dep[x]>dep[y])
		std::swap(x,y);
	res=std::min(res,T::Minor(root,dfn[x],dfn[y]));
	return res;
}

void Invert(int x,int y) {
	T::path p;
	while(top[y]!=top[x]) {
		p.push_back(T::pii(dfn[top[y]],dfn[y]));
		y=fa[top[y]];
	}
	p.push_back(T::pii(dfn[x],dfn[y]));
	reverse(p.begin(),p.end());
	T::Invert(root,p);
}

int main() {
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	read(n),read(m),read(r);
	for(int i=1; i<n; ++i) {
		int x,y;
		read(x),read(y);
		g[x].push_back(y),g[y].push_back(x);
	}
	dfs1(r,0);
	dfs2(r,r);
	T::min[0]=5e7;
	for(int i=1; i<=n; ++i)
		root=T::merge(root,T::newnode(0));
	while(m--) {
		std::string cmd;
		std::cin>>cmd;
		if(cmd=="Increase") {
			int x,y,w;
			read(x),read(y),read(w);
			Increase(x,y,w);
		} else if(cmd=="Sum") {
			int x,y;
			read(x),read(y);
			printf("%lld\n",Sum(x,y));
		} else if(cmd=="Major") {
			int x,y;
			read(x),read(y);
			printf("%lld\n",Major(x,y));
		} else if(cmd=="Minor") {
			int x,y;
			read(x),read(y);
			printf("%lld\n",Minor(x,y));
		} else if(cmd=="Invert") { // utilize the feature
			int x,y;
			read(x),read(y);
			Invert(x,y);
		} else
			assert(0);
	}
	return 0;
}

posted on 2019-01-21 22:05  autoint  阅读(429)  评论(0编辑  收藏  举报

导航