[BZOJ1251]序列终结者 Splay

好累,一天写了三棵树

splay区间翻转、区间加法、区间求最大值

还是要记得注意边界条件,tr[0] = a[0] = mx[0] = -INF


诶下午物理考龊了估计要被老师切死

#include <iostream>
#include <cstdio> 
#include <stack>

#define ls s[t][0]
#define rs s[t][1]

#define INF (1<<30)
#define N 200050
using namespace std;

int a[N],siz[N],tr[N],fa[N],s[N][2],d[N],mx[N],rev[N],ag[N];
int rt,cnt,n,m;
inline void update(int t) { 
	siz[t] = siz[ s[t][0] ] + siz[ s[t][1] ] + 1;
	mx[t] = max( mx[ s[t][0] ] , mx[ s[t][1] ]); 
	mx[t] = max(mx[t],tr[t]);
}
void rot(int x,int &k) {
	int y = fa[x] , z = fa[y] , l = (s[y][0] == x) ^ 1 , r = l ^ 1;
	if (k == y) k = x; else { if (s[z][0] == y) s[z][0] = x; else s[z][1] = x; }
	s[y][l] = s[x][r]; s[x][r] = y;
	fa[x] = z; fa[y] = x; fa[ s[y][l] ] = y;
	update(y); update(x);
}

void pdd(int t) {
	if (rev[t]) {
		rev[t] ^= 1; swap(s[t][0],s[t][1]);
		rev[ s[t][0] ] ^= 1; rev[ s[t][1] ] ^= 1;
	}
	if (s[t][0]) mx[ls] += ag[t] , tr[ls] += ag[t] , ag[ls] += ag[t];
	if (s[t][1]) mx[rs] += ag[t] , tr[rs] += ag[t] , ag[rs] += ag[t];
	ag[t] = 0;
	return ;
}

stack<int> sta;
void access(int x,int k) {
	while (x != k) { sta.push(x); x = fa[x]; }
	while (!sta.empty()) { 
		pdd(sta.top()); 
		sta.pop(); 
	}
}
void SPlay(int x,int &k) {
	access(x,k);
	while (x != k) {
		int y = fa[x] , z = fa[y];
		if (y != k) { if ((s[z][0] == y) ^ (s[y][0] == x)) rot(x,k); else rot(y,k); }
		rot(x,k);
	}
}

void build(int l,int r,int &t,int f) {
	if (l > r) return ;
	int mid = (l + r) >> 1;
	fa[t = ++cnt] = f; d[mid] = t; siz[t] = 1; tr[t] = a[mid];
	if (l == r) return ;
	build(l,mid-1,s[t][0],t);
	build(mid+1,r,s[t][1],t);
	update(t);
}

int kth(int k,int t) {
	pdd(t);
	int tmp = siz[ s[t][0] ] + 1;
	if (k == tmp) return t;
	return tmp > k ? kth(k,s[t][0]) : kth(k-tmp,s[t][1]);
}

void solve() {
	scanf("%d%d",&n,&m);
	a[1] = -INF; a[n+2] = -INF; a[0] = -INF; tr[0] = -INF; mx[0] = -INF;
	build(1,n+2,rt,0);
	while (m--) {
		int cmd,l,r; scanf("%d",&cmd);
		scanf("%d%d",&l,&r); int u = kth(l,rt) , v = kth(r+2,rt);
		SPlay(v,rt); 
		SPlay(u,s[v][0]);
		int t = s[u][1];
		if (cmd == 1) {
			int k; scanf("%d",&k);
			ag[t] += k; mx[t] += k; tr[t] += k;
		}
		if (cmd == 2) rev[t] ^= 1;
		if (cmd == 3) printf("%d\n",mx[t]);
		update(u); update(v);
	}
	return ;
}

int main()
{
	#ifndef ONLINE_JUDGE
		freopen("fuck.in","r",stdin);
		freopen("fuck.out","w",stdout);
	#endif
	solve();
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值