zoukankan      html  css  js  c++  java
  • 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
    ",Sum(x,y));
    		} else if(cmd=="Major") {
    			int x,y;
    			read(x),read(y);
    			printf("%lld
    ",Major(x,y));
    		} else if(cmd=="Minor") {
    			int x,y;
    			read(x),read(y);
    			printf("%lld
    ",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;
    }
    
  • 相关阅读:
    Play Framework + ReactiveMongo 环境搭建
    阿里前端二面(笔试/机试)总结
    ES 6 新特性整理
    Javascript Dom 相关知识整理
    Ajax、CORS、Comet和WebSocket
    XHTML 1.0 标签语义
    Javascript知识整理
    Javascript性能优化(一)
    CSS知识整理
    绘制标准的d3图表
  • 原文地址:https://www.cnblogs.com/autoint/p/10301287.html
Copyright © 2011-2022 走看看