bzoj 1251 简单伸展树

基本操作 翻转 成段加上一个数 求区间最值

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<queue>
#include<set>
#include<cstring>
#include<vector>
using namespace std;
#define L p->ch[0]
#define R p->ch[1]
#define KeyTree root->ch[1]->ch[0]
typedef long long LL;
const int maxn = 611111;
const int INF = 0x77ffffff;
struct Node {
	int val, Max, add;
	int sz;
	bool rev;
	Node *pre, *ch[2];
};
int a[maxn];
struct SplayTree {
	Node *null, *root, data[maxn];
	int cnt;
	Node *NewNode(int x) {
		Node *p = &data[cnt++];
		p->val = p->Max = x;
		p->sz = 1;
		p->add = 0;
		L=R=p->pre=null;
		return p;
	}
	void pushup(Node *p) {
		p->sz = (L->sz)+(R->sz) + 1;
		p->Max=p->val;
		if(L!=null) {
			p->Max=max(p->Max,L->Max);
		}
		if(R!=null) {
			p->Max=max(p->Max,R->Max);
		}
	}
	void pushdown(Node *p) {
		if(p==null) {
			return;
		}
		if(p->rev) {
			swap(L,R);
			L->rev^=1;
			R->rev^=1;
			p->rev=0;
		}
		if(p->add) {
			L->add+=p->add;
			L->val+=p->add;
			L->Max+=p->add;

			R->add+=p->add;
			R->val+=p->add;
			R->Max+=p->add;

			p->add=0;
		}
	}
	void init() {
		cnt=0;
		null=NewNode(-INF);
		null->sz=0;
		root=NewNode(-INF);
		root->ch[1]=NewNode(-INF);
		root->ch[1]->pre=root;
		pushup(root);
	}
	void rotate(Node *x,int c) {
		Node *y=x->pre;
		pushdown(y);
		pushdown(x);
		y->ch[!c]=x->ch[c];
		if(x->ch[c]!=null) {
			x->ch[c]->pre=y;
		}
		x->pre=y->pre;
		if(y->pre!=null) {
			int f=(y->pre->ch[1]==y);
			y->pre->ch[f]=x;
		}
		x->ch[c]=y;
		y->pre=x;
		pushup(y);
	}
	void splay(Node *x,Node *f) {
		pushdown(x);
		while(x->pre!=f) {
			if(x->pre->pre==f) {
				rotate(x,x->pre->ch[0]==x);
			} else {
				Node *y=x->pre;
				Node *z=y->pre;
				if(z->ch[0]==y) {
					if(y->ch[0]==x) {
						rotate(y,1),rotate(x,1);
					} else {
						rotate(x,0),rotate(x,1);
					}
				} else {
					if(y->ch[1]==x) {
						rotate(y,0),rotate(x,0);
					} else {
						rotate(x,1),rotate(x,0);
					}
				}
			}
		}
		if(f==null) {
			root=x;
		}
		pushup(x);
	}
	void RotateTo(int k,Node *f) {
		int tmp;
		Node *t=root;
		pushdown(t);
		while(true) {
			tmp=t->ch[0]->sz;
			if(tmp + 1==k) {
				break;
			}
			if(k<=tmp) {
				t=t->ch[0];
			} else {
				k-=tmp + 1;
				t=t->ch[1];
			}
			pushdown(t);
		}
		splay(t,f);
	}
	Node *build(int l,int r) {
		if(l>r) {
			return null;
		}
		int m=(l+r)>>1;
		Node *p=NewNode(a[m]);
		p->ch[0]=build(l,m-1);
		if(p->ch[0]!=null) {
			p->ch[0]->pre=p;
		}
		p->ch[1]=build(m+1,r);
		if(p->ch[1]!=null) {
			p->ch[1]->pre=p;
		}
		pushup(p);
		return p;
	}
	void add(int l,int r,int v) {
		RotateTo(l,null);
		RotateTo(r,root);
		KeyTree->add+=v;
		KeyTree->val+=v;
		KeyTree->Max+=v;
		pushup(root->ch[1]);
		pushup(root);
	}
	void flip(int l,int r) {
		RotateTo(l,null);
		RotateTo(r,root);
		KeyTree->rev^=1;
	}
	int Max(int l,int r) {
		RotateTo(l,null);
		RotateTo(r,root);
		return KeyTree->Max;
	}
	void Travel(Node *p) {
		pushdown(p);
		if(L!=null) {
			Travel(L);
		}
		printf("%d ",p->val);
		if(R!=null) {
			Travel(R);
		}
	}
	void debug() {
		Travel(root);
		puts("");
	}
}spt;
inline void readT(int &ret) {
	char ch, pre = 0;
	while (ch = getchar(), ch < '0' || ch > '9')
		pre = ch;
	ret = ch ^ 0x30;
	while (ch = getchar(), ch >= '0' && ch <= '9')
		ret = ret*10 + (ch ^ 0x30);
	if (pre == '-')
		ret *= -1;
}
int main() {
	int n, i, m;
	//scanf("%d%d", &n, &m);
	readT(n);
	readT(m);
	spt.init();
	Node* tmp = spt.build(1, n);
	spt.root->ch[1]->ch[0] = tmp;
	tmp->pre = spt.root->ch[1];
	spt.pushup(spt.root->ch[1]);
	spt.pushup(spt.root);

	//spt.debug();
	for (i = 0; i < m; ++i) {
		int t;
		readT(t);
		int l, r, v;
		if (t == 1) {
			readT(l);
			readT(r);
			readT(v);
			++l, ++r;
			spt.add(l - 1, r + 1, v);
		}
		if (t == 2) {
			readT(l);
			readT(r);
			++l, ++r;
			spt.flip(l - 1, r + 1);
		}
		if (t == 3) {
			readT(l);
			readT(r);
			++l, ++r;
			//spt.debug();
			printf("%d\n", spt.Max(l - 1, r + 1));
		}
		//spt.debug();
	}

	return 0;
}
/*
 17 11

 1 8 10 2

 1 6 10 -1

 1 3 7 15

 2 1 15

 1 4 17 -2

 3 5 10



 2 2 10

 3 3 8

 2 6 10

 2 1 10

 3 1 10

 
 */



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值