【NOI 2005】 维修数列

【题目链接】

           点击打开链接

【算法】

           本题所运用的也是Splay的区间操作,但是实现较为困难

            INSERT操作

            将pos splay至根节点,pos+1 splay至根节点的右节点,然后对根节点的右节点的左节点建树即可

            DELETE操作

            将l-1 splay至根节点, r+1 splay至根节点的右节点,直接“砍断”根节点的右节点的左节点

            MAKE_SAME操作

            将l-1 splay至根节点,r+1 splay至根节点的右节点,给根节点的右节点的左节点打上标记

            REVERSE操作

            将l-1 splay至根节点,r+1 splay至根节点的右节点,给根节点的右节点的左节点打上标记

            GET_SUM操作

            将l-1 splay至根节点,r+1 splay至根节点的右节点,直接输出根节点的右节点的左节点的sum

            MAX_SUM操作

            此操作的实现类似于树形DP :

            我们不妨给每个节点增加三个域

            lmax :从这个节点所代表的区间的左端点开始向右延伸的最大和

            rmax :从这个节点所代表的区间的右端点开始像左延伸的最大和

            max : 该节点所代表区间的最大连续子段和

            那么,lmax该如何取值?

            令根节点为root,根节点的左儿子为lc,根节点的右儿子为rc

            我们可以分情况讨论 :

            若lmax[root]不包括root,lmax[root] = lmax[lc]

            lmax[root]包括root,那么 : 若不向右继续延伸,则lmax[root] = tot[lc] + val[root],若向右延伸,

            则lmax[root] = tot[lc] + val[root] + lmax[rc]

            我们只要在这三者中取最大值就可以了

            rmax同理

            那么,max又该如何取值呢?

            我们还是分情况讨论 :

            令根节点为root,根节点的左儿子为rc,根节点的右儿子为rc

            若max[root]不包括root,max[root] = max{max[lc],max[rc]}

            max[root]包括root,那么 : 若不向右也不向左延伸,则max[root] = val[root],若向左延伸,

            则max[root] = val[root] + rmax[lc]

            若向右延伸,则 :

             max[root] = val[root] + lmax[rc]

            若两边同时延伸,则 :

            max[root] = val[root] + rmax[rc] + lmax[lc]

            只需在这五者中取最大值即可

            关于内存池 :

            由于本题数据量较大,我们要进行内存回收,内存回收方法如下 :

            我们建立一个内存池,开始时将所有可用空间都放入内存池,插入一个节点时,我们从内存池弹出一个节点,

            分配给这个节点,删除时,我们将要删除的节点放回内存池,如果是删除一棵子树,则将整棵子树放回内存池

            这个内存池可以用栈,队列,链表等许多数据结构来维护,笔者选用的是栈,由于维护方法比较简单,笔者不再赘述

【代码】

          本题的细节很多,写代码时一定要严谨!

         

#include<bits/stdc++.h>
using namespace std;
#define MAXN 20000
#define MAXX 500000
const int INF = 2e9;

int i,N,M,tot,pos,val;
int a[MAXX+10];
char opt[10];
stack<int> stk;

template <typename T> inline void read(T &x) {
		int f = 1; x = 0;
		char c = getchar();
		for (; !isdigit(c); c = getchar()) { if (c == '-') f = -f; }
		for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
		x *= f;
}

template <typename T> inline void write(T x) {
    if (x < 0) { putchar('-'); x = -x; }
    if (x > 9) write(x/10);
    putchar(x%10+'0');
}

template <typename T> inline void writeln(T x) {
    write(x);
    puts("");
}

struct Splay {
		int root;
		struct Node {
				int fa,son[2],size,lmax,rmax,tot,
						Max,val,lazy;
				bool rev;
		} Tree[MAXX+10];
		inline bool get(int x) {
				return Tree[Tree[x].fa].son[1] == x;
		}
		inline void build(int index,int l,int r) {
				int id,mid;
				mid = (l + r) >> 1;
				Tree[index].lazy = INF;
				Tree[index].rev = 0;
				Tree[index].val = a[mid];
				if (l == r) {
						Tree[index].size = 1;
						Tree[index].lmax = Tree[index].rmax = Tree[index].Max = Tree[index].tot = a[mid];
						return;
				}
				if (l < mid) {
						id = stk.top();
						stk.pop();
						Tree[index].son[0] = id;
						Tree[id].fa = index;
						build(id,l,mid-1);
				}
				if (mid < r) {
						id = stk.top();
						stk.pop();
						Tree[index].son[1] = id;
						Tree[id].fa = index;
						build(id,mid+1,r);
				}
				update(index);
		}
		inline void update(int index) {
				if (!index) return;
				Tree[index].tot = Tree[Tree[index].son[0]].tot + Tree[Tree[index].son[1]].tot + Tree[index].val;
				Tree[index].size = Tree[Tree[index].son[0]].size + Tree[Tree[index].son[1]].size + 1;
				Tree[index].lmax = max(Tree[Tree[index].son[0]].lmax,Tree[Tree[index].son[0]].tot+max(Tree[Tree[index].son[1]].lmax,0)+Tree[index].val);
				Tree[index].rmax = max(Tree[Tree[index].son[1]].rmax,Tree[Tree[index].son[1]].tot+max(Tree[Tree[index].son[0]].rmax,0)+Tree[index].val);
				Tree[index].Max = max(Tree[Tree[index].son[0]].Max,max(Tree[Tree[index].son[1]].Max,Tree[index].val+max(Tree[Tree[index].son[0]].rmax,0)+max(Tree[Tree[index].son[1]].lmax,0)));
		}
		inline void pushdown(int index) {
				int tmp;
				if (Tree[index].lazy != INF) {
						tmp = Tree[index].lazy;
						Tree[index].lazy = INF;
						if (Tree[index].son[0]) Tree[Tree[index].son[0]].tot = Tree[Tree[index].son[0]].size * tmp;
						if (Tree[index].son[1]) Tree[Tree[index].son[1]].tot = Tree[Tree[index].son[1]].size * tmp;
						if (Tree[index].son[0]) Tree[Tree[index].son[0]].val = tmp;
						if (Tree[index].son[1]) Tree[Tree[index].son[1]].val = tmp;	
						if (Tree[index].son[0]) Tree[Tree[index].son[0]].lmax = Tree[Tree[index].son[0]].rmax = Tree[Tree[index].son[0]].Max = max(tmp,Tree[Tree[index].son[0]].size*tmp);
						if (Tree[index].son[1]) Tree[Tree[index].son[1]].lmax = Tree[Tree[index].son[1]].rmax = Tree[Tree[index].son[1]].Max = max(tmp,Tree[Tree[index].son[1]].size*tmp);
						if (Tree[index].son[0]) Tree[Tree[index].son[0]].lazy = tmp;
						if (Tree[index].son[1]) Tree[Tree[index].son[1]].lazy = tmp;
				}
				if (Tree[index].rev) {
						swap(Tree[index].son[0],Tree[index].son[1]);
						swap(Tree[Tree[index].son[0]].lmax,Tree[Tree[index].son[0]].rmax);
						swap(Tree[Tree[index].son[1]].lmax,Tree[Tree[index].son[1]].rmax);
						Tree[Tree[index].son[0]].rev ^= 1;
						Tree[Tree[index].son[1]].rev ^= 1;
						Tree[index].rev = 0;
				}
		}
		inline int query_pos(int x) {
				int index = root;
				while (true) {
						pushdown(index);
						if (x > Tree[Tree[index].son[0]].size) {
								x -= Tree[Tree[index].son[0]].size;
								if (x == 1) return index;
								--x;
								index = Tree[index].son[1];
						} else index = Tree[index].son[0];
				}		
		}
		inline void clear(int index) {
				Tree[Tree[index].fa].son[get(index)] = 0;
				Tree[index].fa = 0;
				stk.push(index);
				if (Tree[index].son[0]) clear(Tree[index].son[0]);
				if (Tree[index].son[1]) clear(Tree[index].son[1]);	
		}
		inline void Insert(int index) {
				int id;
				int x = query_pos(index),
						y = query_pos(index+1);
				splay(x,0); splay(y,root);
				id = stk.top(); 
				stk.pop();
				build(id,1,tot);
				Tree[Tree[root].son[1]].son[0] = id;
				Tree[id].fa = Tree[root].son[1];
				update(Tree[root].son[1]);
				update(root);
		}
		inline void rotate(int x) {
				int f = Tree[x].fa,g = Tree[f].fa,
				tmpx = get(x),tmpf = get(f);
				pushdown(f); pushdown(x);
				if (!f) return;
				Tree[f].son[tmpx] = Tree[x].son[tmpx^1];
				if (Tree[x].son[tmpx^1]) Tree[Tree[x].son[tmpx^1]].fa = f;
				Tree[x].son[tmpx^1] = f;
				Tree[f].fa = x;
				Tree[x].fa = g;
				if (g) Tree[g].son[tmpf] = x;
				update(f);
				update(x);
		}
		inline void splay(int x,int pos) {
				int f;
				for (f = Tree[x].fa; (f = Tree[x].fa) != pos; rotate(x)) {
						if (Tree[f].fa != pos) 
								rotate(get(f) == get(x) ? (f) : (x));
				}
				if (!pos) root = x;
		}
		inline void modify(int l,int r,int v) {
				int x = query_pos(l-1),
						y = query_pos(r+1);
				splay(x,0); splay(y,root);
				int tmp = Tree[Tree[root].son[1]].son[0];
				Tree[tmp].val = Tree[tmp].lazy = v;
				Tree[tmp].tot = v * Tree[tmp].size;
				Tree[tmp].lmax = Tree[tmp].rmax = Tree[tmp].Max = max(Tree[tmp].size*v,v);
				update(Tree[root].son[1]);
				update(root);
		}
		inline void reverse(int l,int r) {
				int x = query_pos(l-1),
						y = query_pos(r+1);
				splay(x,0); splay(y,root);
				Tree[Tree[Tree[root].son[1]].son[0]].rev ^= 1;
				swap(Tree[Tree[Tree[root].son[1]].son[0]].lmax,Tree[Tree[Tree[root].son[1]].son[0]].rmax);
		}
		inline void erase(int l,int r) {
				int x = query_pos(l-1),
						y = query_pos(r+1);
				splay(x,0); splay(y,root);
				clear(Tree[Tree[root].son[1]].son[0]);
				Tree[Tree[root].son[1]].son[0] = 0;
				update(Tree[root].son[1]);
				update(root);
		}
		int get_sum(int l,int r) {
				int x = query_pos(l-1),
						y = query_pos(r+1);
				splay(x,0); splay(y,root);
				return Tree[Tree[Tree[root].son[1]].son[0]].tot;
		}
		int max_sum(int l,int r) {
				int x = query_pos(l-1),
						y = query_pos(r+1);
				splay(x,0); splay(y,root);
				return Tree[Tree[Tree[root].son[1]].son[0]].Max;
		}
} T;

int main() {
		
		read(N); read(M);
		
		for (i = 2; i <= MAXX; i++) stk.push(i);
		
		a[1] = a[N+2] = -INF;
		for (i = 2; i <= N + 1; i++) read(a[i]);
		
		T.Tree[0].lmax = T.Tree[0].rmax = T.Tree[0].Max = -INF;
		T.root = 1;
		T.build(1,1,N+2);
		
		while (M--) {
				scanf("%s",&opt);
				if (opt[0] == 'I') {
						read(pos); read(tot);
						for (i = 1; i <= tot; i++) read(a[i]);
						T.Insert(pos+1);
						N += tot;
				}	else if (opt[0] == 'D') {
						read(pos); read(tot);
						T.erase(pos+1,pos+tot);
						N -= tot;
				} else if (opt[0] == 'M' && opt[2] == 'K') {
						read(pos); read(tot); read(val);
						T.modify(pos+1,pos+tot,val);
				} else if (opt[0] == 'R') {
						read(pos); read(tot);
						T.reverse(pos+1,pos+tot);
				} else if (opt[0] == 'G') {
						read(pos); read(tot);
						writeln(T.get_sum(pos+1,pos+tot));
				} else if (opt[0] == 'M' && opt[2] == 'X') {
						writeln(T.max_sum(2,N+1));
				}                          
		}
		
		return 0;
	
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值