CODEVS-1758-维护数列-NOI2005-splay

描述

要求支持区间插入、区间修改、区间翻转、区间删除、区间求和 和求和最大的子列.


分析

  • 从最开始学完splay做了翻转区间后就想做这个题目, 结果WA了N次后失去调试的信心, 40分收场(这题暴力30分)
  • 快省选了想拿出来再做一下, 因为splay的区间操作这个题算是最全的了, 不做一下的话总担心模版是错的.
  • 然后做了好长时间...终于不耐烦了拿HZWER的改了改, 直到改到所有操作和我的都写的一模一样——除了标记下传. 然后就很开(伤)心地接受了这个现实.
  • 在网上看每个人写的标记下传都不一样, 有的写的简单有的很复杂(比如HZWER). 但一种标记下传对应一种维护方式吧, 看网上很少有写如何处理细节的, 我就写详细点吧.
  • 首先, mls, mrs, maxs分别记录左、右端开始的最大子序列和, 和整段区间的最大子序列和.
  • 规定如果整段区间为负值, mls和mrs可以取0, 而maxs必须取一个存在的数, 这样也是为了维护起来方便吧.
  • 那么mls可以取左子结点的mls、左子结点的sum+根结点的权值+右子结点的mls. mrs同理.
  • maxs可以取左子结点的maxs、右子结点的maxs、左子结点的mrs+根结点权值+右子结点的mls.
  • 这就是mls、mrs最小为0的优势.
  • 在标记下传时下传的实际上是子结点的标记, 而根结点的标记实际上已经在此之前生效了. 这样可以避免在旋转时出错. 旋转里的那个 ch[p][d] 的标记可能没有生效.
  • 遇到带区间修改的题目都要用这种标记下传的方式吧..
  • 又想起原来写过的区间翻转类的题目, 那里的标记下传只需要下传当前节点的即可, 那是因为翻转不影响最大值、不影响求和. 而区间修改会影响.

#include 
   
   
    
    
#include 
    
    
     
     
using namespace std;

const int INF = 0x3f3f3f3f;
const int maxn = 3000000;

int n, m;
int fa[maxn], ch[maxn][2], id[maxn];
int mls[maxn], mrs[maxn], maxs[maxn], s[maxn], rech[maxn], v[maxn], sumv[maxn];
bool mdf[maxn], rev[maxn];

#define lc ch[o][0]
#define rc ch[o][1]

void update(int o) {
	s[o] = s[lc] + s[rc] + 1;
	sumv[o] = sumv[lc] + sumv[rc] + v[o];
	maxs[o] = max(maxs[lc], maxs[rc]);
	maxs[o] = max(maxs[o], mrs[lc] + v[o] + mls[rc]);
	mls[o] = max(mls[lc], sumv[lc] + v[o] + mls[rc]);
	mrs[o] = max(mrs[rc], sumv[rc] + v[o] + mrs[lc]);
}

void pushdown(int o) {
	if(mdf[o]) {
		mdf[o] = rev[o] = 0;
		if(lc) mdf[lc] = 1, v[lc] = v[o], sumv[lc] = v[o]*s[lc];
		if(rc) mdf[rc] = 1, v[rc] = v[o], sumv[rc] = v[o]*s[rc];
		if(v[o] >= 0) {
			if(lc) mls[lc] = mrs[lc] = maxs[lc] = sumv[lc];
			if(rc) mls[rc] = mrs[rc] = maxs[rc] = sumv[rc];
		} else {
			if(lc) mls[lc] = mrs[lc] = 0, maxs[lc] = v[o];
			if(rc) mls[rc] = mrs[rc] = 0, maxs[rc] = v[o];
		}
	}
	if(rev[o]) {
		rev[o]^=1;
		rev[lc]^=1;
		rev[rc]^=1;
		swap(mls[lc], mrs[lc]);
		swap(mls[rc], mrs[rc]);
		swap(ch[lc][0], ch[lc][1]);
		swap(ch[rc][0], ch[rc][1]);
	}
}

void rotate(int& o, int x)  {
	int p = fa[x], q = fa[p];
	bool d = (ch[p][1] == x), d2 = (ch[q][1] == p);
	if(o == p) o = x; else ch[q][d2] = x;
	fa[x] = q; fa[p] = x; fa[ch[p][d] = ch[x][d^1]] = p;
	ch[x][d^1] = p; update(p); update(x);
}

void splay(int& o, int x) {
	while(o != x) {
		int p = fa[x], q = fa[p];
		if(o != p)
			if(ch[p][0] == x^ch[q][0] == p) rotate(o, x); 
			else rotate(o, p);
		rotate(o, x);
	}
}

void build(int L, int R, int p, int d) {
	if(L > R) return;
	int o = (L+R)>>1;
	ch[p][d] = o; fa[o] = p;
	build(L, o-1, o, 0);
	build(o+1, R, o, 1);
	update(o);
}

int kth(int o, int k) {
	pushdown(o);
	if(s[lc] + 1 == k) return o;
	else if(s[lc] >= k) return kth(lc, k);
	else return kth(rc, k-s[lc]-1);
}


int o, pos, tot, val;

void insert() {
	splay(o, kth(o, pos+1));
	splay(rc, kth(o, pos+2));
	for(int i = n+1; i <= n+tot; i++) scanf("%d", &v[i]);
	build(n+1, n+tot, rc, 0);
	n += tot; //
	update(rc); update(o);
}

void remove() {
	splay(o, kth(o, pos));
	splay(rc, kth(o, pos + tot + 1));
	ch[rc][0] = 0;
	update(rc); update(o);
}

void modify() {
	splay(o, kth(o, pos));
	splay(rc, kth(o, pos + tot + 1));
	int p = ch[rc][0];
	v[p] = val;
	mdf[p] = 1;
	sumv[p] = v[p]*s[p];
	if(val >= 0) mls[p] = mrs[p] = maxs[p] = sumv[p];
	else mls[p] = mrs[p] = 0, maxs[p] = v[p];
	update(rc); update(o);
}

void rever() {
	splay(o, kth(o, pos));
	splay(rc, kth(o, pos + tot + 1));
	if(!mdf[o]) {
		int p = ch[rc][0];
		rev[p]^=1;
		swap(ch[p][0], ch[p][1]);
		swap(mls[p], mrs[p]);
	}
	update(rc); update(o);
}

void query() {
	splay(o, kth(o, pos));
	splay(rc, kth(o, pos + tot + 1));
	printf("%d\n", sumv[ch[rc][0]]);
}

int main()
{
	scanf("%d %d", &n, &m); n += 2;
	v[1] = v[n] = maxs[0] = -INF; //
	for(int i = 2; i < n; i++) scanf("%d", &v[i]);
	build(1, n, 0, 0);
	o = (n+1)>>1;
	
	for(int i = 1; i <= m; i++) {
		char opt[10];
		scanf("%s", opt);
		switch(opt[2]) {
			case 'S': scanf("%d %d", &pos, &tot); insert(); break;
			case 'L': scanf("%d %d", &pos, &tot); remove(); break;
			case 'V': scanf("%d %d", &pos, &tot); rever(); break;
			case 'T': scanf("%d %d", &pos, &tot); query(); break;
			case 'K': scanf("%d %d %d", &pos, &tot, &val); modify(); break;
			case 'X': printf("%d\n", maxs[o]);
		}
	}
	return 0;
}
#include 
     
     
      
      
#include 
      
      
       
       
using namespace std;

const int INF = 0x3f3f3f3f;
const int maxn = 3000000;

int n, m;
int ch[maxn][2], id[maxn];
int mls[maxn], mrs[maxn], maxs[maxn], s[maxn], rech[maxn], v[maxn], sumv[maxn];
bool mdf[maxn], rev[maxn];

#define lc ch[o][0]
#define rc ch[o][1]

void update(int o) {
	s[o] = s[lc] + s[rc] + 1;
	sumv[o] = sumv[lc] + sumv[rc] + v[o];
	maxs[o] = max(maxs[lc], maxs[rc]);
	maxs[o] = max(maxs[o], mrs[lc] + v[o] + mls[rc]);
	mls[o] = max(mls[lc], sumv[lc] + v[o] + mls[rc]);
	mrs[o] = max(mrs[rc], sumv[rc] + v[o] + mrs[lc]);
}

void pushdown(int o) {
	if(mdf[o]) {
		mdf[o] = rev[o] = 0;
		if(lc) mdf[lc] = 1, v[lc] = v[o], sumv[lc] = v[o]*s[lc];
		if(rc) mdf[rc] = 1, v[rc] = v[o], sumv[rc] = v[o]*s[rc];
		if(v[o] >= 0) {
			if(lc) mls[lc] = mrs[lc] = maxs[lc] = sumv[lc];
			if(rc) mls[rc] = mrs[rc] = maxs[rc] = sumv[rc];
		} else {
			if(lc) mls[lc] = mrs[lc] = 0, maxs[lc] = v[o];
			if(rc) mls[rc] = mrs[rc] = 0, maxs[rc] = v[o];
		}
	}
	if(rev[o]) {
		rev[o]^=1;
		rev[lc]^=1;
		rev[rc]^=1;
		swap(mls[lc], mrs[lc]);
		swap(mls[rc], mrs[rc]);
		swap(ch[lc][0], ch[lc][1]);
		swap(ch[rc][0], ch[rc][1]);
	}
}

void rotate(int& o, int d) {
	int p = ch[o][d^1]; ch[o][d^1] = ch[p][d]; ch[p][d] = o;
	update(o); update(p); o = p;
}

int cmp(int o, int k) {
	if(s[lc] + 1 == k) return -1;
	return k < s[lc] + 1 ? 0 : 1;
}

void splay(int& o, int k) {
	pushdown(o);
	int d = cmp(o, k);
	if(d == -1) return;
	if(d == 1) k -= (s[lc] + 1);
	int p = ch[o][d];
	pushdown(p);
	int d2 = cmp(p, k);
	int k2 = (d2 == 0 ? k : k-s[ch[p][0]]-1);
	if(d2 != -1) {
		splay(ch[p][d2], k2);
		if(d == d2) rotate(o, d^1); else rotate(ch[o][d], d);
	}
	rotate(o, d^1);
}

void build(int& o, int L, int R) {
	if(L > R) return;
	o = (L+R)>>1;
	build(lc, L, o-1);
	build(rc, o+1, R);
	update(o);
}

void getInterval(int& o, int pos, int tot) {
	splay(o, pos);
	splay(rc, pos + tot - s[lc]);
}


int o, pos, tot, val;

void insert() {
	getInterval(o, pos+1, 0);
	for(int i = n+1; i <= n+tot; i++) scanf("%d", &v[i]);
	build(ch[rc][0], n+1, n+tot);
	n += tot; //
	update(rc); update(o);
}

void remove() {
	getInterval(o, pos, tot);
	ch[rc][0] = 0;
	update(rc); update(o);
}

void modify() {
	getInterval(o, pos, tot);
	int p = ch[rc][0];
	v[p] = val;
	mdf[p] = 1;
	sumv[p] = v[p]*s[p];
	if(val >= 0) mls[p] = mrs[p] = maxs[p] = sumv[p];
	else mls[p] = mrs[p] = 0, maxs[p] = v[p];
	update(rc); update(o);
}

void rever() {
	getInterval(o, pos, tot);
	if(!mdf[o]) {
		int p = ch[rc][0];
		rev[p]^=1;
		swap(ch[p][0], ch[p][1]);
		swap(mls[p], mrs[p]);
	}
	update(rc); update(o);
}

void query() {
	getInterval(o, pos, tot);
	printf("%d\n", sumv[ch[rc][0]]);
}

int main()
{
	scanf("%d %d", &n, &m); n += 2;
	v[1] = v[n] = maxs[0] = -INF; //
	for(int i = 2; i < n; i++) scanf("%d", &v[i]);
	build(o, 1, n);
	
	for(int i = 1; i <= m; i++) {
		char opt[10];
		scanf("%s", opt);
		switch(opt[2]) {
			case 'S': scanf("%d %d", &pos, &tot); insert(); break;
			case 'L': scanf("%d %d", &pos, &tot); remove(); break;
			case 'V': scanf("%d %d", &pos, &tot); rever(); break;
			case 'T': scanf("%d %d", &pos, &tot); query(); break;
			case 'K': scanf("%d %d %d", &pos, &tot, &val); modify(); break;
			case 'X': printf("%d\n", maxs[o]);
		}
	}
	return 0;
}
      
      
     
     
    
    
   
   


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值