BZOJ1500: [NOI2005]维修数列 Splay维护序列

//#include<bits/stdc++.h>  
//#pragma comment(linker, "/STACK:1024000000,1024000000")   
#include<stdio.h>  
#include<algorithm>  
#include<queue>  
#include<string.h>  
#include<iostream>  
#include<math.h>                    
#include<set>  
#include<map>  
#include<vector>  
#include<iomanip> 
#include<bitset>
using namespace std;         //

#define ll long long  
#define pb push_back  
#define FOR(a) for(int i=1;i<=a;i++) 
#define sqr(a) (a)*(a)
#define dis(a,b) sqrt(sqr(a.x-b.x)+sqr(a.y-b.y))
ll qp(ll a,ll b,ll mod){
	ll t=1;while(b){if(b&1)t=t*a%mod;b>>=1;a=a*a%mod;}return t;
}
struct DOT{int x;int y;};
const int dx[4]={0,0,-1,1};
const int dy[4]={1,-1,0,0};
const int inf=0x3f3f3f3f;  
const ll mod=1e9+7;

const int maxn=5e5+6;

int n,m;
int a[maxn];

int rt=0;
int c[maxn][2],parent[maxn];
int val[maxn],size[maxn];
int lx[maxn],rx[maxn],mx[maxn],sum[maxn];
int tag[maxn],rev[maxn];	
int id[maxn];
queue<int>Q;

inline void pushup(int x){
	int l=c[x][0],r=c[x][1];
	size[x]=size[l]+size[r]+1;						//子树大小
	sum[x]=sum[l]+sum[r]+val[x];					//区间和
	mx[x]=max(max(mx[r],mx[l]),val[x]+rx[l]+lx[r]);	//最大子段和
	lx[x]=max(lx[l],sum[l]+val[x]+lx[r]);			//最大前缀
	rx[x]=max(rx[r],sum[r]+val[x]+rx[l]);			//最大后缀
}
void pushdown(int x){
	int l=c[x][0],r=c[x][1];
	if(tag[x]){
		tag[x]=rev[x]=0;
		if(l)tag[l]=1,val[l]=val[x],sum[l]=val[x]*size[l];
		if(r)tag[r]=1,val[r]=val[x],sum[r]=val[x]*size[r];
		if(val[x]>=0){
			if(l)lx[l]=rx[l]=mx[l]=sum[l];
			if(r)lx[r]=rx[r]=mx[r]=sum[r];
		}else{
			if(l)lx[l]=rx[l]=0;mx[l]=val[x];
			if(r)lx[r]=rx[r]=0,mx[r]=val[x];
		}
	}
	if(rev[x]){
		rev[x]=0;rev[l]^=1;rev[r]^=1;
		swap(lx[l],rx[l]);swap(lx[r],rx[r]);
		swap(c[l][0],c[l][1]);swap(c[r][0],c[r][1]);
	}
}
void rotate(int x,int &k){
	int y=parent[x],z=parent[y],d=c[y][1]==x;
	if(y==k)k=x;else c[z][c[z][1]==y]=x;parent[x]=z;
	c[y][d]=c[x][d^1];parent[c[x][d^1]]=y;
	c[x][d^1]=y;parent[y]=x;
	pushup(y);pushup(x);
}
void splay(int x,int &k){
	while(x!=k){
		int y=parent[x],z=parent[y];
		if(y!=k) (c[y][0]==x^c[z][0]==y)?rotate(x,k):rotate(y,k);
		rotate(x,k);
	}
}

inline int find(int x,int k){
	pushdown(x);
	int lc=c[x][0],rc=c[x][1];
	if(k>size[lc]+1)return find(rc,k-size[lc]-1);
	else if(k<=size[lc])return find(lc,k);
	else return x;
}
inline int Split(int l,int r){
	int x=find(rt,l);
	int y=find(rt,r);

	splay(x,rt);splay(y,c[x][1]);
	return c[y][0];
}

void init(){for(int i=n+3;i<maxn;i++)Q.push(i);}

inline void recycle(int x){
	int &l=c[x][0],&r=c[x][1];
	if(l)recycle(l);if(r)recycle(r);
	Q.push(x);
	parent[x]=l=r=tag[x]=rev[x]=0;
}
void erase(int l,int r){
	int x=Split(l,r),y=parent[x];
	recycle(x);
	c[y][0]=0;pushup(y);pushup(parent[y]);
}

void build(int l,int r,int f){
	if(l>r)return;
	int m=l+r>>1,now=id[m],pa=id[f];
	val[now]=a[m];parent[now]=pa;
	c[pa][m>=f]=now;
	if(l==r){
		mx[now]=sum[now]=val[now];
		lx[now]=rx[now]=max(0,val[now]);
		size[now]=1;
		return;
	}
	build(l,m-1,m);build(m+1,r,m);
	pushup(now);
}
void insert(int l,int tot){
	for(int i=1;i<=tot;i++)scanf("%d",&a[i]);
	for(int i=1;i<=tot;i++)id[i]=Q.front(),Q.pop();
	build(1,tot,0);
	int z=id[1+tot>>1],x=find(rt,l+1),y=find(rt,l+2);	//标号右移
	splay(x,rt);splay(y,c[x][1]);
	parent[z]=y;c[y][0]=z;
	pushup(y);pushup(x);
}
int query(int l,int r){
	int x=Split(l,r);
	return sum[x];
}
void rever(int l,int r){
	int x=Split(l,r),y=parent[x];
	if(!tag[x]){
		rev[x]^=1;
		swap(c[x][0],c[x][1]);
		swap(lx[x],rx[x]);
		pushup(y);pushup(parent[y]);
	}
}
void update(int l,int r,int v){
	int x=Split(l,r),y=parent[x];
	val[x]=v;tag[x]=1;sum[x]=size[x]*v;
	if(v>=0)lx[x]=rx[x]=mx[x]=sum[x];
	else lx[x]=rx[x]=0,mx[x]=v;
	pushup(y);pushup(parent[y]);
}

char s[20];
int main(){
	scanf("%d%d",&n,&m);
	mx[0]=a[1]=a[n+2]=-inf;
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i+1]);
	}
	for(int i=1;i<=n+2;i++)id[i]=i;

	init();
	build(1,n+2,0);rt=n+3>>1;

	for(int i=1;i<=m;i++){
		scanf("%s",s);
		if(s[2]=='X')printf("%d\n",mx[rt]);
		else{
			int k,tot;scanf("%d",&k);scanf("%d",&tot);
			if(s[2]=='S')insert(k,tot);
			if(s[2]=='L')erase(k,k+tot+1);
			if(s[2]=='K'){int x;scanf("%d",&x);update(k,k+tot+1,x);}
			if(s[2]=='V')rever(k,k+tot+1);
			if(s[2]=='T')printf("%d\n",query(k,k+tot+1));
		}
	}
}

通过split提取目标区间,由于旋转到根影响的父节点就2个

支持O(logn)区间反转,O(元素个数)加入元素

回收节点编号的操作挺棒的,以后不用担心数组版数据结构溢编号了

posted @ 2018-02-06 00:14  Drenight  阅读(163)  评论(0编辑  收藏  举报