poj 3580 伸展树重口味题

http://poj.org/problem?id=3580

注意,inf设的不要太小,还有对于题目输入数据的各种处理(可能有非法数据),要注意判断,具体见代码

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int inf = ~0u>>2;
#define L  ch[x][0]
#define R  ch[x][1] 
#define KT (ch[ ch[rt][1] ][0])
const int maxn = 200010;  
struct SplayTree {
	int sz[maxn];
	int ch[maxn][2];
	int pre[maxn];
	int rt,top;
	inline int min(int a,int b) {return a<b?a:b;}
	inline void down(int x){
		if(!x) return ;
		if(flip[x]) {
			flip[ L ] ^= 1;
			flip[ R ] ^= 1;
			swap(L,R);
			flip[x]=0;
		}
		if(add[x]) {
			if(L) {
				mi[L]  += add[x];
				add[L] += add[x];
				val[L] += add[x];
			}
			if(R){
				mi[R]  += add[x];
				add[R] += add[x];
				val[R] += add[x];
			}
			add[x]=0;
		}
	}
	inline void up(int x){
		mi[x]=min(val[x],min(mi[ L ],mi[ R ]));
		sz[x]= 1 + sz[ L ] + sz[ R ];
	}
	inline void Rotate(int x,int f){
		int y=pre[x];
		down(y);
		down(x);
		ch[y][!f] = ch[x][f];
		pre[ ch[x][f] ] = y;
		pre[x] = pre[y];
		if(pre[x]) ch[ pre[y] ][ ch[pre[y]][1] == y ] =x;
		ch[x][f] = y;
		pre[y] = x;
		up(y);
	}
	inline void Splay(int x,int goal){//将x旋转到goal的下面
		down(x);//防止pre[x]就是目标点,下面的循环就进不去了,x的信息就传不下去了
		while(pre[x] != goal){
			down(pre[pre[x]]); down(pre[x]);down(x);//在旋转之前需要先下传标记,因为节点的位置可能会发生改变
			if(pre[pre[x]] == goal) Rotate(x , ch[pre[x]][0] == x);
			else   {
				int y=pre[x],z=pre[y];
				int f = (ch[z][0]==y);
				if(ch[y][f] == x) Rotate(x,!f),Rotate(x,f);
				else Rotate(y,f),Rotate(x,f);
			}
		}
		up(x);
		if(goal==0) rt=x;
	}
	inline void RTO(int k,int goal){//将第k位数旋转到goal的下面
		int x=rt;
		down(x);
		while(sz[ L ]+1 != k) {
			if(k < sz[ L ] + 1 ) x=L;
			else {
				k-=(sz[ L ]+1);
				x = R;
			}
			down(x);
		}
		Splay(x,goal);
	}
	void vist(int x){
		if(x){
			printf("结点%2d : 左儿子  %2d   右儿子  %2d   %2d  mi:%d  sum:%2d   add:%2d\n",x,L,R,val[x],mi[x],sum[x],add[x]);
			vist(L);
			vist(R);
		}
	}
	void debug(){	vist(rt);}
	void Newnode(int &x,int c,int f){
		x=++top;   
		L = R = 0;   sz[x]=1;  pre[x]=f;
		mi[x]=val[x]=c;  flip[x]=add[x]=0;  
	}
	inline void build(int &x,int l,int r,int f){
		if(l>r) return ;
		int m=l+r>>1;
		Newnode(x,num[m],f);
		build(L , l , m-1 , x);
		build(R , m+1 , r , x);
		pre[x]=f;
		up(x);
	}
	inline void init(int n){
		ch[0][0]=ch[0][1]=pre[0]=sz[0]=0;
		rt=top=0; 
		flip[0]=val[0]=add[0]=0; mi[0]=inf;
		Newnode(rt,inf,0);
		Newnode(ch[rt][1],inf,rt);
		sz[rt]=2;
		for(int i=1;i<=n;i++) scanf("%d",&num[i]);
		build(KT,1,n,ch[rt][1]);
		up(ch[rt][1]);	up(rt);
	}
	void MIN() {
		int x,y;
		scanf("%d%d",&x,&y);
		if(x>y) swap(x,y);
		RTO(x,0);
		RTO(y+2,rt);
		printf("%d\n",mi[KT]);
	}
	void ADD() {
		int x,y,d;
		scanf("%d%d%d",&x,&y,&d);
		if(x>y) swap(x,y);
		RTO(x,0);
		RTO(y+2,rt);
		add[KT] += d;
		val[KT] += d;
		mi[KT] += d;
	}
	void REVERSE(){
		int x,y;
		scanf("%d%d",&x,&y);
		if(x>y) swap(x,y);
		RTO(x,0);
		RTO(y+2,rt);
		flip[KT] ^= 1;
	}
	void INSERT() {
		int x,p;
		scanf("%d%d",&x,&p);
		RTO(x+1,0);
		RTO(x+2,rt);
		Newnode(KT,p,ch[rt][1]);
		up(ch[rt][1]);up(rt);
	}
	void DELETE() {
		int x;
		scanf("%d",&x);
		RTO(x,0);
		RTO(x+2,rt);
		KT = 0;
		up(ch[rt][1]);  up(rt);
	}
	void REVOLVE() {
		int x,y,t,l,r;
		scanf("%d%d%d",&x,&y,&t);
		if(x>y) swap(x,y);
		t%=(y-x+1);
		t=(t+y-x+1) % (y-x+1);
		if(t==0) return ;
		l=y-t+1,r=y;
		RTO(l,0);
		RTO(r+2,rt);
		int tmp=KT;
		KT=0; 
		up(ch[rt][1]);up(rt);
		RTO(x,0);
		RTO(x+1,rt);
		KT=tmp; pre[tmp] = ch[rt][1];
		up(ch[rt][1]);up(rt);
	}
	int mi[maxn];
	int num[maxn];
	int add[maxn];
	int sum[maxn];
	int flag;
	int flip[maxn];
	int val[maxn];
}spt;
int main() {
	int n,m;
	scanf("%d",&n);
	spt.init(n);
	char op[10];
	scanf("%d",&m);
	while(m--) {
		scanf("%s",op);
		if(op[0]=='A') {
			spt.ADD();
		} else if(op[0]=='M') {
			spt.MIN();
		} else if(op[0]=='I') {
			spt.INSERT();
		} else if(op[0]=='D') {
			spt.DELETE();
		} else if(strcmp(op,"REVERSE") == 0) {
			spt.REVERSE();
		} else if(strcmp(op,"debug") == 0){
			spt.debug();
		} else {
			spt.REVOLVE();
		}
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值