首页 > 代码库 > 【bzoj1500】[NOI2005]维修数列

【bzoj1500】[NOI2005]维修数列

题目描述

技术分享

输入

输入的第1 行包含两个数N 和M(M ≤20 000),N 表示初始时数列中数的个数,M表示要进行的操作数目。
第2行包含N个数字,描述初始时的数列。
以下M行,每行一条命令,格式参见问题描述中的表格。
任何时刻数列中最多含有500 000个数,数列中任何一个数字均在[-1 000, 1 000]内。
插入的数字总数不超过4 000 000个,输入文件大小不超过20MBytes。

输出

对于输入数据中的GET-SUM和MAX-SUM操作,向输出文件依次打印结果,每个答案(数字)占一行。

样例输入

9 8
2 -6 3 5 1 -5 -3 6 3
GET-SUM 5 4
MAX-SUM
INSERT 8 3 -5 7 2
DELETE 12 1
MAKE-SAME 3 3 2
REVERSE 3 6
GET-SUM 5 4
MAX-SUM

样例输出

-1
10
1
10


题解

做了4小时的Splay“裸题”。

大概就是各种细节处理一下就行了。

这里ls和rs的数的个数可以为0,但ts的数的个数一定大于0,应该可以在代码中pushup部分理解。

ts[0]要赋成极小值,否则pushup时可能会因使用到0节点而不为真正值。

当某数为负数时,ls和rs为0,但是ts为v,即小于0。这点在pushdown中尤其突出。

pushdown中有无儿子的问题,一定要判断。

不能开特大空间,所以需要循环利用下标,把能用的下标存到一个队列中,加入时取出队首,删除时加到队尾。

搞定细节以后(话说不是先敲大体在搞细节吗),就是splay裸题。

220行丑丑的代码。。

#include <cstdio>
#include <cstring>
#include <queue>
#define N 600010
using namespace std;
int sum[N] , v[N] , ls[N] , rs[N] , ts[N] , si[N] , rev[N] , tag[N] , c[2][N] , fa[N] , root;
char str[20];
queue<int> q;
inline int read()
{
	int num = 0 , f = 1; char ch = getchar();
	while(ch < ‘0‘ || ch > ‘9‘){if(ch == ‘-‘)f = -1; ch = getchar();}
	while(ch >= ‘0‘ && ch <= ‘9‘) num = (num << 3) + (num << 1) + ch - ‘0‘ , ch = getchar();
	return num * f;
}
void pushup(int k)
{
	int l = c[0][k] , r = c[1][k];
	sum[k] = sum[l] + sum[r] + v[k];
	ls[k] = max(ls[l] , sum[l] + v[k] + ls[r]);
	rs[k] = max(rs[r] , sum[r] + v[k] + rs[l]);
	ts[k] = max(max(ts[l] , ts[r]) , rs[l] + v[k] + ls[r]);
	si[k] = si[l] + si[r] + 1;
}
void pushdown(int k)
{
	int l = c[0][k] , r = c[1][k];
	if(tag[k] != 0x3f3f3f3f)
	{
		if(l) sum[l] = si[l] * tag[k] , v[l] = tag[l] = tag[k];
		if(r) sum[r] = si[r] * tag[k] , v[r] = tag[r] = tag[k];
		if(tag[k] > 0)
		{
			if(l) ls[l] = rs[l] = ts[l] = si[l] * tag[k];
			if(r) ls[r] = rs[r] = ts[r] = si[r] * tag[k];
		}
		else
		{
			if(l) ls[l] = rs[l] = 0 , ts[l] = tag[k];
			if(r) ls[r] = rs[r] = 0 , ts[r] = tag[k];
		}
		tag[k] = 0x3f3f3f3f;
	}
	if(rev[k])
	{
		swap(c[0][l] , c[1][l]);
		swap(c[0][r] , c[1][r]);
		swap(ls[l] , rs[l]);
		swap(ls[r] , rs[r]);
		rev[l] ^= 1;
		rev[r] ^= 1;
		rev[k] = 0;
	}
}
void build(int l , int r , int f)
{
	if(l > r) return;
	int mid = (l + r) >> 1;
	build(l , mid - 1 , mid);
	build(mid + 1 , r , mid);
	fa[mid] = f;
	c[mid > f][f] = mid;
	pushup(mid);
}
void rotate(int &k , int x)
{
	int y = fa[x] , z = fa[y] , l , r;
	l = (c[0][y] != x);
	r = l ^ 1;
	if(y == k) k = x;
	else if(c[0][z] == y) c[0][z] = x;
	else c[1][z] = x;
	fa[x] = z;
	fa[y] = x;
	fa[c[r][x]] = y;
	c[l][y] = c[r][x];
	c[r][x] = y;
	pushup(y);
	pushup(x);
}
void splay(int &k , int x)
{
	while(k != x)
	{
		int y = fa[x] , z = fa[y];
		if(y != k)
		{
			if(c[0][z] == y ^ c[0][y] == x) rotate(k , x);
			else rotate(k , y);
		}
		rotate(k , x);
	}
}
int find(int k , int x)
{
	pushdown(k);
	if(x <= si[c[0][k]]) return find(c[0][k] , x);
	else if(x > si[c[0][k]] + 1) return find(c[1][k] , x - si[c[0][k]] - 1);
	else return k;
}
void update(int l , int r , int x)
{
	int ta , tb , t;
	ta = find(root , l - 1);
	splay(root , ta);
	tb = find(root , r + 1);
	splay(c[1][root] , tb);
	t = c[0][c[1][root]];
	sum[t] = si[t] * x;
	if(x > 0) ls[t] = rs[t] = ts[t] = si[t] * x;
	else ls[t] = rs[t] = 0 , ts[t] = x;
	v[t] = tag[t] = x;
	pushup(c[1][root]);
	pushup(root);
}
void rever(int l , int r)
{
	int ta , tb , t;
	ta = find(root , l - 1);
	splay(root , ta);
	tb = find(root , r + 1);
	splay(c[1][root] , tb);
	t = c[0][c[1][root]];
	swap(c[0][t] , c[1][t]);
	swap(ls[t] , rs[t]);
	rev[t] ^= 1;
}
void cls(int k)
{
	if(k)
	{
		int l = c[0][k] , r = c[1][k];
		cls(l) , q.push(k) , cls(r);
		tag[k] = 0x3f3f3f3f;
		rev[k] = sum[k] = si[k] = ls[k] = rs[k] = ts[k] = c[0][k] = c[1][k] = fa[k] = 0;
	}
}
int main()
{
	int n , m , i , p , t , x , ta , tb , id;
	n = read() , m = read();
	for(i = 2 ; i <= n + 1 ; i ++ )
		v[i] = read();
	memset(tag , 0x3f , sizeof(tag));
	ts[0] = 0xc0000000;
	build(1 , n + 2 , 0);
	root = (n + 3) >> 1;
	for(i = n + 3 ; i <= 600005 ; i ++ ) q.push(i);
	while(m -- )
	{
		scanf("%s" , str);
		switch(str[2])
		{
			case ‘S‘:
			{
				p = read() , t = read();
				for(i = 1 ; i <= t ; i ++ )
				{
					ta = find(root , p + i);
					splay(root , ta);
					tb = find(root , p + i + 1);
					splay(c[1][root] , tb);
					x = read();
					id = q.front() , q.pop();
					v[id] = x;
					fa[id] = c[1][root];
					c[0][c[1][root]] = id;
					pushup(c[0][c[1][root]]);
					pushup(c[1][root]);
					pushup(root);
				}
				break;
			}
			case ‘L‘:
			{
				p = read() , t = read();
				ta = find(root , p);
				splay(root , ta);
				tb = find(root , p + t + 1);
				splay(c[1][root] , tb);
				cls(c[0][c[1][root]]);
				c[0][c[1][root]] = 0;
				pushup(c[1][root]);
				pushup(root);
				break;
			}
			case ‘K‘:
			{
				p = read() , t = read() , x = read();
				update(p + 1 , p + t , x);
				break;
			}
			case ‘V‘:
			{
				p = read() , t = read();
				rever(p + 1 , p + t);
				break;
			}
			case ‘T‘:
			{
				p = read() , t = read();
				ta = find(root , p);
				splay(root , ta);
				tb = find(root , p + t + 1);
				splay(c[1][root] , tb);
				printf("%d\n" , sum[c[0][c[1][root]]]);
				break;
			}
			default:
			{
				ta = find(root , 1);
				splay(root , ta);
				tb = find(root , si[root]);
				splay(c[1][root] , tb);
				printf("%d\n" , ts[c[0][c[1][root]]]);
			}
		}
	}
	return 0;
}

 

【bzoj1500】[NOI2005]维修数列