BZOJ 1500: [NOI2005]维修数列

1500: [NOI2005]维修数列

Time Limit: 10 Sec  Memory Limit: 64 MB
Submit: 12880  Solved: 4112
[Submit][Status][Discuss]

Description

Input

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

Output

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

Sample Input

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

Sample Output

-1
10
1
10

HINT

Source

分析:

很久之前就写过...但是没写过...QAQ...没想到这道题还是写了一年(怎么又跨年了...

操作什么的其实就是把线段树换成了Splay...

insert:
把posi+1转到root,posi转到左儿子,新插入的作为posi的右儿子
delete:
把posi+tot转到root,posi-1转到左儿子,删掉posi-1的右儿子
make_same:
把posi+tot转到root,posi-1转到左儿子,posi-1的右儿子修改
reverse:
转法和上面一样,打标记
get_sum:
同上
max_sum:
每个节点维护lsum,rsum,msum

比较麻烦的就是一些边界问题...Zig_Zag的code可以完美滴处理这些问题,然而我只会特判...向Zig_Zag神犇学习...

代码:

其实我的代码还是有缺陷的...只不过可以过掉BZOJ的数据...

正确的写法应该是Zig_Zag那样的...如果把我的code的每次操作完的那两次旋转去掉是过不了的...

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
//by NeighThorn
#define inf 0x3f3f3f3f
using namespace std;

const int maxn=1000000+5;

int tail,stk[maxn];
int n,m,now,tot,root,w[maxn],no[maxn],ls[maxn],rs[maxn],fa[maxn],siz[maxn],sum[maxn],rev[maxn],lmax[maxn],rmax[maxn],mmax[maxn],lazy[maxn];

char opt[13];

inline void reverse(int x){
	if(x==0)
		return;
	swap(ls[x],rs[x]);
	swap(lmax[x],rmax[x]);
}

inline void make_same(int x,int y){
	if(x==0)
		return;
	w[x]=y;sum[x]=siz[x]*y;
	lmax[x]=rmax[x]=mmax[x]=max(y,sum[x]);//bu neng wei kong
}

inline void push_down(int x){
	if(x==0)
		return;
	if(rev[x])
		reverse(ls[x]),reverse(rs[x]),rev[ls[x]]^=1,rev[rs[x]]^=1,rev[x]=0;
	if(lazy[x]!=-inf)
		make_same(ls[x],lazy[x]),make_same(rs[x],lazy[x]),lazy[ls[x]]=lazy[rs[x]]=lazy[x],lazy[x]=-inf;
}

inline void update(int x){
	if(x==0)
		return;
	lmax[x]=max(lmax[ls[x]],sum[ls[x]]+w[x]+max(0,lmax[rs[x]]));
	rmax[x]=max(rmax[rs[x]],sum[rs[x]]+w[x]+max(0,rmax[ls[x]]));
	mmax[x]=max(max(mmax[ls[x]],mmax[rs[x]]),w[x]+max(0,rmax[ls[x]])+max(0,lmax[rs[x]]));
	sum [x]=sum[ls[x]]+sum[rs[x]]+w[x];
	siz [x]=siz[ls[x]]+siz[rs[x]]+1;
}

inline void zig(int x){
	int y=fa[x];
	update(x);update(y);
	if(rs[x])
		ls[y]=rs[x],fa[rs[x]]=y;
	else
		ls[y]=0;
	fa[x]=fa[y];
	if(fa[x]){
		if(ls[fa[y]]==y)
			ls[fa[y]]=x;
		else
			rs[fa[y]]=x;
	}
	fa[y]=x,rs[x]=y;
	update(y),update(x);
}

inline void zag(int x){
	int y=fa[x];
	update(x);update(y);
	if(ls[x])
		rs[y]=ls[x],fa[ls[x]]=y;
	else
		rs[y]=0;
	fa[x]=fa[y];
	if(fa[x]){
		if(ls[fa[y]]==y)
			ls[fa[y]]=x;
		else
			rs[fa[y]]=x;
	}
	fa[y]=x,ls[x]=y;
	update(y),update(x);
}

inline void relax(int x,int y){
	if(x!=y)
		relax(fa[x],y);
	push_down(x);
}

inline void splay(int x,int z){
	relax(x,z);
	while(fa[x]!=z){
		int y=fa[x];
		if(fa[y]==z){
			if(ls[y]==x)
				zig(x);
			else
				zag(x);
		}
		else{
			if(ls[fa[y]]==y){
				if(ls[y]==x)
					zig(y),zig(x);
				else
					zag(x),zig(x);
			}
			else{
				if(rs[y]==x)
					zag(y),zag(x);
				else
					zig(x),zag(x);
			}
		}
	}
	update(x);
	if(!z)
		root=x;
	else
		update(z);
}

inline int get_num(void){
	if(tail)
		return stk[tail--];
	return ++tot;
}

inline int assign(int x){
	int tmp=get_num();
	rev[tmp]=0;
	w[tmp]=no[x];
	lazy[tmp]=-inf;
	lmax[tmp]=rmax[tmp]=mmax[tmp]=-inf;
	return tmp;
}

inline int build(int l,int r){
	if(l==r){
		int tmp=assign(l);
		update(tmp);return tmp;
	}
	int mid=(l+r)>>1,L=0,R=0,tmp=assign(mid);
	if(l<mid)
		L=build(l,mid-1);
	if(r>mid)
		R=build(mid+1,r);
	if(L)
		ls[tmp]=L,fa[L]=tmp;
	if(R)
		rs[tmp]=R,fa[R]=tmp;
	update(tmp);
	return tmp;
}

inline void del(int x){
	if(x==0)
		return;
	stk[++tail]=x;
	fa[x]=rev[x]=0;lazy[x]=-inf;
	lmax[x]=rmax[x]=mmax[x]=-inf;
	if(ls[x])
		del(ls[x]);
	if(rs[x])
		del(rs[x]);
	ls[x]=rs[x]=0;
}

inline int find(int rt,int x){
	push_down(rt);
	if(siz[ls[rt]]+1==x)
		return rt;
	else if(siz[ls[rt]]+1>x)
		return find(ls[rt],x);
	else
		return find(rs[rt],x-siz[ls[rt]]-1);
}

inline int read(void){
	char ch=getchar();int x=0,f=1;
	while(!(ch>=‘0‘&&ch<=‘9‘)){
		if(ch==‘-‘)
			f=-1;
		ch=getchar();
	}
	while(ch>=‘0‘&&ch<=‘9‘)
		x=x*10+ch-‘0‘,ch=getchar();
	return f*x;
}

signed main(void){
	memset(ls,0,sizeof(ls));
	memset(rs,0,sizeof(rs));
	memset(fa,0,sizeof(fa));
	memset(rev,0,sizeof(rev));
	memset(sum,0,sizeof(sum));
	memset(siz,0,sizeof(siz));
	memset(lmax,-inf,sizeof(lmax));
	memset(rmax,-inf,sizeof(rmax));
	memset(mmax,-inf,sizeof(mmax));
	memset(lazy,-inf,sizeof(lazy));
	tot=tail=0;
	n=read(),m=read();now=n;
	for(int i=1;i<=n;i++)
		no[i]=read();
	root=build(1,n);int pos,tot,x;
	while(m--){
		scanf("%s",opt);
		if(opt[0]==‘I‘){
			pos=read(),tot=read();
			for(int i=1;i<=tot;i++)
				no[i]=read();
			int tmproot=build(1,tot);
			if(now==0)
				root=tmproot;
			else if(pos==0)
				splay(find(root,pos+1),0),ls[root]=tmproot,fa[tmproot]=root,update(root);
			else if(pos==now)
				splay(find(root,pos),0),rs[root]=tmproot,fa[tmproot]=root,update(root);
			else
				splay(find(root,pos+1),0),splay(find(root,pos),root),rs[ls[root]]=tmproot,fa[tmproot]=ls[root],update(ls[root]),update(root);
			now+=tot;
		}
		else if(opt[0]==‘D‘){
			pos=read(),tot=read();
			if(pos==1&&pos+tot-1==now)
				root=0;
			else if(pos==1)
				splay(find(root,pos+tot),0),del(ls[root]),ls[root]=0,update(root);
			else if(pos+tot-1==now)
				splay(find(root,pos-1),0),del(rs[root]),rs[root]=0,update(root);
			else
				splay(find(root,pos+tot),0),splay(find(root,pos-1),root),del(rs[ls[root]]),rs[ls[root]]=0,update(ls[root]),update(root);
			now-=tot;
		}
		else if(opt[0]==‘M‘&&opt[2]==‘K‘){
			pos=read(),tot=read(),x=read();
			if(pos==1&&pos+tot-1==now)
				make_same(root,x),lazy[root]=x;
			else if(pos==1)
				splay(find(root,pos+tot),0),make_same(ls[root],x),lazy[ls[root]]=x;
			else if(pos+tot-1==now)
				splay(find(root,pos-1),0),make_same(rs[root],x),lazy[rs[root]]=x;
			else
				splay(find(root,pos+tot),0),splay(find(root,pos-1),root),make_same(rs[ls[root]],x),lazy[rs[ls[root]]]=x;
		}
		else if(opt[0]==‘R‘){
			pos=read(),tot=read();
			if(pos==1&&pos+tot-1==now)
				reverse(root),rev[root]^=1;
			else if(pos==1)
				splay(find(root,pos+tot),0),reverse(ls[root]),rev[ls[root]]^=1;
			else if(pos+tot-1==now)
				splay(find(root,pos-1),0),reverse(rs[root]),rev[rs[root]]^=1;
			else
				splay(find(root,pos+tot),0),splay(find(root,pos-1),root),reverse(rs[ls[root]]),rev[rs[ls[root]]]^=1;
		}
		else if(opt[0]==‘G‘){
			pos=read(),tot=read();
			if(tot==0)
				puts("0");
			else if(pos==1&&pos+tot-1==now)
				splay(find(root,now),0),splay(find(root,1),0),printf("%d\n",sum[root]);
			else if(pos==1)
				splay(find(root,pos+tot),0),printf("%d\n",sum[ls[root]]);
			else if(pos+tot-1==now)
				splay(find(root,pos-1),0),printf("%d\n",sum[rs[root]]);
			else
				splay(find(root,pos+tot),0),splay(find(root,pos-1),root),printf("%d\n",sum[rs[ls[root]]]);
		}
		else
			splay(find(root,now),0),splay(find(root,1),0),printf("%d\n",mmax[root]);
		splay(find(root,1),0);splay(find(root,now),0);
	}
	return 0;
}//Cap ou pas cap. Cap.

  



By NeighThorn

时间: 2024-08-05 11:00:27

BZOJ 1500: [NOI2005]维修数列的相关文章

BZOJ 1500: [NOI2005]维修数列( splay )

splay..... ------------------------------------------------------------------------ #include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #include<queue> #define rep( i , n ) for( int i = 0 ; i < n ; ++

1500: [NOI2005]维修数列

1500: [NOI2005]维修数列 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 12952  Solved: 4138[Submit][Status][Discuss] Description Input 输入的第1 行包含两个数N 和M(M ≤20 000),N 表示初始时数列中数的个数,M表示要进行的操作数目.第2行包含N个数字,描述初始时的数列.以下M行,每行一条命令,格式参见问题描述中的表格.任何时刻数列中最多含有500 000个数,

【BZOJ】1500: [NOI2005]维修数列

[算法]splay [题解]数据结构 感谢Occult的模板>_<:HYSBZ 1500 维修数列 #include<cstdio> #include<cctype> #include<cstring> #include<queue> #include<algorithm> using namespace std; const int maxn=5e5+10,inf=0x3f3f3f3f; int n,m,root,a[maxn],t

【BZOJ】1500: [NOI2005]维修数列(splay+变态题)

http://www.lydsy.com/JudgeOnline/problem.php?id=1500 模板不打熟你确定考场上调试得出来? 首先有非常多的坑点...我遇到的第一个就是,如何pushup............sad.. 写了一大串...可是感觉...写不下去了...看别人怎么写吧... orz 首先这个节点代表的这个区间我们维护mxl和mxr表示整个区间从左向右和从右向左能得到的最大序列和.. 然后我无脑不思考没有用好我们的定义,写了一大串的转移... 其实就是几个字.. vo

1500. [NOI2005]维修数列【平衡树-splay】

Description 请写一个程序,要求维护一个数列,支持以下 6 种操作: 请注意,格式栏 中的下划线‘ _ ’表示实际输入文件中的空格 Input 输入的第1 行包含两个数N 和M(M ≤20 000),N 表示初始时数列中数的个数,M表示要进行的操作数目. 第2行包含N个数字,描述初始时的数列. 以下M行,每行一条命令,格式参见问题描述中的表格. 任何时刻数列中最多含有500 000个数,数列中任何一个数字均在[-1 000, 1 000]内. 插入的数字总数不超过4 000 000个,

HYSBZ 1500 [NOI2005]维修数列 splay

解题思路:终于把这道splay神题A掉了,splay专题也算是告一段落了,这个题主要的坑点,还是旋转和区间合并结合. 解题代码: 1 // File Name: hysbz1500.cpp 2 // Author: darkdream 3 // Created Time: 2015年04月10日 星期五 10时41分03秒 4 5 #include<vector> 6 #include<list> 7 #include<map> 8 #include<set>

BZOJ1500: [NOI2005]维修数列[splay ***]

1500: [NOI2005]维修数列 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 12278  Solved: 3880[Submit][Status][Discuss] Description Input 输入的第1 行包含两个数N 和M(M ≤20 000),N 表示初始时数列中数的个数,M表示要进行的操作数目.第2行包含N个数字,描述初始时的数列.以下M行,每行一条命令,格式参见问题描述中的表格.任何时刻数列中最多含有500 000个数,

Splay必做题 [NOI2005]维修数列

1500: [NOI2005]维修数列 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 6577  Solved: 1978[Submit][Status] Description Input 输入文件的第1行包含两个数N和M,N表示初始时数列中数的个数,M表示要进行的操作数目.第2行包含N个数字,描述初始时的数列.以下M行,每行一条命令,格式参见问题描述中的表格. Output 对于输入数据中的GET-SUM和MAX-SUM操作,向输出文件依次打印

[NOI2005] 维修数列

mnesia在频繁操作数据的过程可能会报错:** WARNING ** Mnesia is overloaded: {dump_log, write_threshold},可以看出,mnesia应该是过载了.这个警告在mnesia dump操作会发生这个问题,表类型为disc_only_copies .disc_copies都可能会发生. 如何重现这个问题,例子的场景是多个进程同时在不断地mnesia:dirty_write/2 mnesia过载分析 1.抛出警告是在mnesia 增加dump