[bzoj1500][NOI2005]维修数列

终于写过了,在这里庆祝一下。

在开始前先推荐一篇论文运用伸展树解决数列维护问题,jzp大神写的关于splay树区间操作的方法。

这题很考验代码的细节能力。(大神可以忽略下面弱菜的一些弱弱心得了)

首先是初始化,初始化中的两个节点的初值应要因题而异,在本题中因为要求一个节点的max值,故两个节点的初值不能随便赋值,而应把初值赋为-INF,否则会导致结果错误。(在几千的数据里差错真心纠结....)

之后GET-SUM操作和DELETE操作还有INSER T操作和MAKE-SAME操作都是标准操作,找splay模板写即可,其中要注意一点的是删除时要注意回收内存。

REVERSE操作中,标记往下传时要对左右子树的标记xor 1,而不能简单地赋值为1(因为有可能在pushdown前子树已经要翻转)

MAX-SUM操作比较麻烦,可以用三个标记分别为lmax,rmax,mmax表示从左到右最大的sum值,从右起最大的sum值,还有整棵子树中sum值,然后求节点的lmax值可以分为三种情况,分别为左子树的lmax,整棵左子树的sum+节点的值,还有左子树的值+节点的值+右子树的lmax。求rmax同样也可以类似地分为三种情况。

求mmax的值首先可以想到取左右子树中mmax值较大的,之后再以节点为中心,向左右拓展找较大的序列,看这个序列的sum值是否比mmax大,若大则更新即可。

这道题几乎把splay的一些常用操作都涉及到了,故要学splay的话还是应该找个时间静心做一下。

下面先上代码(求大神不鄙视...)

const
	MAXN=500000;
	INF=10000000;
type
	date=record
		ch:array[0..1]of longint;
		sz,v,f,sum,same,rev,mmax,rmax,lmax:longint;
	end;
var
	n,m,top,root,tst,p,tot,x,i:longint;s:string;
	a,st:array[1..MAXN+10]of longint;
	t:array[0..MAXN+10]of date;
procedure swap(var a,b:longint);
var c:longint;
begin
	c:=a;a:=b;b:=c;
end;
function max(a,b:longint):longint;
begin
	if(a>b)then exit(a) else exit(b);
end;
procedure pushdown(k:longint);
begin
	if(k=0)then exit;
	if(t[k].rev=1)then
	begin
		if(t[k].ch[0]<>0)then t[t[k].ch[0]].rev:=t[t[k].ch[0]].rev xor 1;
		if(t[k].ch[1]<>0)then t[t[k].ch[1]].rev:=t[t[k].ch[1]].rev xor 1;
		swap(t[k].ch[0],t[k].ch[1]);swap(t[k].lmax,t[k].rmax);
		t[k].rev:=0;
	end;
	if(t[k].same<>INF)then
	begin
		if(t[k].ch[0]<>0)then t[t[k].ch[0]].same:=t[k].same;
		if(t[k].ch[1]<>0)then t[t[k].ch[1]].same:=t[k].same;
		t[k].v:=t[k].same;
		t[k].sum:=t[k].same*t[k].sz;
		if(t[k].same<0)then begin t[k].mmax:=t[k].v;t[k].lmax:=t[k].v;t[k].rmax:=t[k].v end
		else begin t[k].mmax:=t[k].sum;t[k].lmax:=t[k].sum;t[k].rmax:=t[k].sum end;
		t[k].same:=INF;
	end;
end;
procedure pushup(k:longint);
var l,r:longint;
begin
	if(k=0)then exit;
	l:=t[k].ch[0];r:=t[k].ch[1];
	pushdown(k);pushdown(l);pushdown(r);
	t[k].sz:=1+t[l].sz+t[r].sz;
	t[k].sum:=t[k].v+t[l].sum+t[r].sum;
	t[k].mmax:=-INF;t[k].lmax:=-INF;t[k].rmax:=-INF;
	if(l<>0)then t[k].lmax:=max(t[k].lmax,t[l].lmax);
	if(r<>0)then t[k].lmax:=max(t[k].lmax,t[l].sum+t[k].v+t[r].lmax);
	t[k].lmax:=max(t[k].lmax,t[l].sum+t[k].v);
	if(r<>0)then t[k].rmax:=max(t[k].rmax,t[r].rmax);
	if(l<>0)then t[k].rmax:=max(t[k].rmax,t[r].sum+t[k].v+t[l].rmax);
	t[k].rmax:=max(t[k].rmax,t[r].sum+t[k].v);
	if(l<>0)then t[k].mmax:=max(t[k].mmax,t[l].mmax);
	if(r<>0)then t[k].mmax:=max(t[k].mmax,t[r].mmax);
	t[k].mmax:=max(t[k].mmax,max(0,t[l].rmax)+t[k].v+max(0,t[r].lmax));
end;
function cmp(x,k:longint):longint;
begin
	if(t[x].ch[0]=k)then exit(0) else exit(1);
end;
procedure rotate(k,c:longint);
var x:longint;
begin
	x:=t[k].f;
	pushdown(x);pushdown(k);
	t[x].ch[c xor 1]:=t[k].ch[c];t[t[k].ch[c]].f:=x;t[k].ch[c]:=x;
	t[k].f:=t[x].f;
	if(t[x].f<>0)then t[t[x].f].ch[cmp(t[x].f,x)]:=k;
	t[x].f:=k;
	pushup(x);
end;
procedure splay(k,goal:longint);
var x,y,f1,f2:longint;
begin
	pushdown(k);
	while(t[k].f<>goal)do
	begin
		x:=t[k].f;y:=t[x].f;
		if(y=goal)then rotate(k,cmp(x,k)xor 1)
		else begin
			f1:=cmp(y,x);f2:=cmp(x,k);
			if(f1=f2)then begin rotate(x,f1 xor 1);rotate(k,f1 xor 1) end
			else begin rotate(k,f2 xor 1);rotate(k,f1 xor 1) end;
		end;
	end;
	pushup(k);
	if(goal=0)then root:=k;
end;
procedure rotateto(k,goal:longint);
var i:longint;
begin
	i:=root;
	pushdown(i);
	while(t[t[i].ch[0]].sz<>k)do
	begin
		if(k<t[t[i].ch[0]].sz)then i:=t[i].ch[0]
		else begin
			k:=k-t[t[i].ch[0]].sz-1;i:=t[i].ch[1];
		end;
		pushdown(i);
	end;
	splay(i,goal);
end;
procedure del(k:longint);
begin
	if(k=0)then exit;
	inc(tst);st[tst]:=k;
	del(t[k].ch[0]);del(t[k].ch[1]);
end;
procedure newnode(var x:longint;f,k:longint);
begin
	if(tst<>0)then begin x:=st[tst];dec(tst) end
	else begin inc(top);x:=top end;
	t[x].ch[0]:=0;t[x].ch[1]:=0;
	t[x].sz:=1;t[x].same:=INF;t[x].rev:=0;t[x].f:=f;
	t[x].v:=k;t[x].mmax:=k;t[x].lmax:=k;t[x].rmax:=k;
end;
procedure maketree(var x:longint;l,r,f:longint);
var mid:longint;
begin
	if(l>r)then exit;
	mid:=(l+r)>>1;
	newnode(x,f,a[mid]);
	maketree(t[x].ch[0],l,mid-1,x);
	maketree(t[x].ch[1],mid+1,r,x);
	pushup(x);
end;
procedure readin(n:longint);
var i:longint;
begin
	for i:=1 to n do read(a[i]);
	readln;
	maketree(t[t[root].ch[1]].ch[0],1,n,t[root].ch[1]);
end;
procedure init;
begin
	tst:=0;
	newnode(root,0,-INF);
	newnode(t[root].ch[1],root,-INF);
	readin(n);
	pushup(t[root].ch[1]);pushup(root);
end;
procedure getchar;
var c:char;
begin
	s:='';
	read(c);
	while(not eoln)and(c<>' ')do
	begin
		s:=s+c;read(c);
	end;
	if(c<>' ')then s:=s+c;
end;
procedure print(k:longint);
begin
	if(k=0)then exit;
	pushdown(k);
	print(t[k].ch[0]);
	writeln('node:',k,' lc:',t[k].ch[0],' rc:',t[k].ch[1],' f:',t[k].f,' sz:',t[k].sz,' v:',t[k].v,
		' sum:',t[k].sum,' rev:',t[k].rev);
	print(t[k].ch[1]);
end;
procedure debug;
begin
	writeln;
	writeln(root);
	print(root);
	writeln;
end;
begin
//assign(input,'sequence.in');reset(input);
//assign(output,'sequence.out');rewrite(output);
	readln(n,m);
	init;
	for i:=1 to m do
	begin
//		writeln('==========',i,'=========');
		getchar;
		if(s='INSERT')then
		begin
			read(p,tot);rotateto(p,0);rotateto(p+1,root);readin(tot);
		end;
		if(s='DELETE')then
		begin
			readln(p,tot);
			rotateto(p-1,0);rotateto(p+tot,root);
			del(t[t[root].ch[1]].ch[0]);t[t[root].ch[1]].ch[0]:=0;
		end;
		if(s='MAKE-SAME')then
		begin
			readln(p,tot,x);
			rotateto(p-1,0);rotateto(p+tot,root);
			t[t[t[root].ch[1]].ch[0]].same:=x;
		end;
		if(s='REVERSE')then
		begin
			readln(p,tot);
			rotateto(p-1,0);rotateto(p+tot,root);
			t[t[t[root].ch[1]].ch[0]].rev:=t[t[t[root].ch[1]].ch[0]].rev xor 1;
		end;
		if(s='GET-SUM')then
		begin
			readln(p,tot);
			rotateto(p-1,0);rotateto(p+tot,root);
			writeln(t[t[t[root].ch[1]].ch[0]].sum);
		end;
		if(s='MAX-SUM')then
		begin
			readln;writeln(t[root].mmax);
		end;
		pushup(t[root].ch[1]);pushup(root);
	end;
//close(input);close(output);
end.


推荐一下squarefk大神的代码

#include <cstdio>
#include <cstring>
#include <algorithm>
#define REP(i,n) for (int i=1;i<=n;++i)
using namespace std;
   
const int INF=1999999999,MAXN=500050;
struct TTTT{int sam,rev,num,size,sum,s0,s1,s2,s[2],p;} t[MAXN];
void Sets(int p,int k,int d) {if (t[p].s[d]=k) t[k].p=p;}
int Which(int k) {return t[t[k].p].s[1]==k;}
int n,m,x,k,top,root,a[MAXN],st[MAXN];
char s[11];
   
void Pushdown(int k) {
    if (t[k].rev) {
        if (t[k].s[0]) t[t[k].s[0]].rev^=1;
        if (t[k].s[1]) t[t[k].s[1]].rev^=1;
        swap(t[k].s[0],t[k].s[1]);
        swap(t[k].s0,t[k].s1);
        t[k].rev=0;
    }
    if (t[k].sam!=INF) {
        if (t[k].s[0]) t[t[k].s[0]].sam=t[k].sam;
        if (t[k].s[1]) t[t[k].s[1]].sam=t[k].sam;
        t[k].num=t[k].sam;
        t[k].sum=t[k].size*t[k].num;
        if (t[k].num<0) t[k].s0=t[k].s1=t[k].s2=t[k].num;
        else t[k].s0=t[k].s1=t[k].s2=t[k].num*t[k].size;
        t[k].sam=INF;
    }
}
   
void Relax(int &a,int b) {if (b>a) a=b;}
void Update(int k) {
    Pushdown(k);
    Pushdown(t[k].s[0]);
    Pushdown(t[k].s[1]);
    t[k].size=t[t[k].s[0]].size+t[t[k].s[1]].size+1;
    t[k].sum=t[t[k].s[0]].sum+t[t[k].s[1]].sum+t[k].num;
    t[k].s0=t[k].s1=t[k].s2=-INF;
    if (t[k].s[0]) Relax(t[k].s0,t[t[k].s[0]].s0);
    if (t[k].s[1]) Relax(t[k].s0,t[t[k].s[0]].sum+t[k].num+t[t[k].s[1]].s0);
    Relax(t[k].s0,t[t[k].s[0]].sum+t[k].num);
    if (t[k].s[1]) Relax(t[k].s1,t[t[k].s[1]].s1);
    if (t[k].s[0]) Relax(t[k].s1,t[t[k].s[1]].sum+t[k].num+t[t[k].s[0]].s1);
    Relax(t[k].s1,t[t[k].s[1]].sum+t[k].num);
    if (t[k].s[0]) Relax(t[k].s2,t[t[k].s[0]].s2);
    if (t[k].s[1]) Relax(t[k].s2,t[t[k].s[1]].s2);
    Relax(t[k].s2,max(0,t[t[k].s[0]].s1)+max(0,t[t[k].s[1]].s0)+t[k].num);
}
   
void Rot(int k) {
    int p=t[k].p,d=Which(k);
    Sets(p,t[k].s[d^1],d);
    if (!t[p].p) t[root=k].p=0;
    else Sets(t[p].p,k,Which(p));
    Sets(k,p,d^1);
    Update(p);
}
   
void Splay(int k,int goal) {
    while (t[k].p!=goal) {
        if (t[t[k].p].p==goal) Rot(k);
        else
            if (Which(k)==Which(t[k].p))
                {Rot(t[k].p);Rot(k);}
            else
                {Rot(k);Rot(k);}
    }
    Update(k);
}
   
int Get() {
    char c=getchar(); int ret=0;
    while ((c!='-')&&((c<'0')||(c>'9'))) c=getchar();
    if (c=='-') return -Get();
    while ((c>='0')&&(c<='9')) ret=ret*10+c-'0',c=getchar();
    return ret;
}
   
int New(int num) {
    int k=st[top--];
    t[k].size=1; t[k].rev=0; t[k].sam=INF;
    t[k].num=t[k].sum=t[k].s0=t[k].s1=t[k].s2=num;
    return k;
}
   
void Del(int k) {
    if (!k) return;
    st[++top]=k;
    Del(t[k].s[0]);
    Del(t[k].s[1]);
}
   
int Build(int l,int r) {
    if (l>r) return 0;
    int m=(l+r)>>1;
    int k=New(a[m]);
    t[k].s[0]=Build(l,m-1); Sets(k,t[k].s[0],0);
    t[k].s[1]=Build(m+1,r); Sets(k,t[k].s[1],1);
    Update(k);
    return k;
}
   
int Find(int x) {
    int k=root;
    for (;;) {
        Pushdown(k);
        if (x==t[t[k].s[0]].size+1) break;
        if (x<t[t[k].s[0]].size+1) k=t[k].s[0];
        else
            x-=t[t[k].s[0]].size+1,k=t[k].s[1];
    }
    return k;
}
   
int main() {
    top=MAXN-1;
    REP(i,top) st[i]=i;
    n=Get(); m=Get();
    REP(i,n) a[i]=Get(); a[0]=a[n+1]=-10000;
    root=Build(0,n+1);
    REP(mm,m) {
        scanf("%s",s);
        if (!strcmp(s,"MAX-SUM")) printf("%d\n",t[root].s2); else
        if (!strcmp(s,"INSERT")) {
            x=Get(); k=Find(x+1);Splay(k,0); k=Find(x+2);Splay(k,root);
            n=Get(); REP(i,n) a[i]=Get(); Sets(t[root].s[1],Build(1,n),0);
        } else {
            x=Get(); k=Find(x);Splay(k,0); k=Find(x+Get()+1);Splay(k,root);
            if (!strcmp(s,"GET-SUM")) printf("%d\n",t[t[t[root].s[1]].s[0]].sum);
            if (!strcmp(s,"REVERSE")) t[t[t[root].s[1]].s[0]].rev^=1;
            if (!strcmp(s,"MAKE-SAME")) t[t[t[root].s[1]].s[0]].sam=Get();
            if (!strcmp(s,"DELETE")) {Del(t[t[root].s[1]].s[0]);Sets(t[root].s[1],0,0);}
        }
        Update(t[root].s[1]); Update(root);
    }
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值