zoukankan      html  css  js  c++  java
  • [HNOI2011]括号修复

    【出处】

    HNOI2011Day1

    【题目描述】

    给定一个长度为N的由“(”和“)”组成的字符串和M个操作。

    要求实现四个操作:

    1、统一:将[a,b]之间的所有括号改成c(“(”或“)”)

    2、翻转:将[a,b]之间的字符串翻转

    3、改变:将[a,b]之间的‘(’变成‘)’

    4、询问:询问[a,b]之间的字符串至少要改变多少位才能变成合法的括号序列。

    N,M≤100000

    【算法分析】

    此题非常巧妙,可以成功转化成类似最大连续子序列的求解方式,并运用Splay进行维护。

    对于一个已知的括号,我们该如何求出询问的答案?

    比如)((())((这样一个,我们把符合的一层层去掉,就变成了)(((,那么很显然答案是3。并且易得,所有的字符串化简后必是))...)((...(的形式(或全是)或(),答案就是wps_clip_image-21258。关键就是如何求出个数来。考虑左起的),我们发现,当一个字符串)))))())中有了一个(,就相当于连续的(减少了1。如果我们把(看成+1,)看成-1,那么答案就是从最左边开始连续最小的一段。同样的从右边可算出(。即我们把原串的(看成+1,)看成-1,问题就变成了求左起连续最小一段和右起连续最大一段。

    由于还涉及到修改,我们考虑用Splay动态维护,首先要维护基本的五个:father,left,right,size,s(这个元素的值)。涉及到翻转,所以我们维护四个答案需要的信息:xl,xr,yl,yr,sum,表示左起、右起最多的+1个数,左起、右起最多的-1个数,子树和,且这里xl,xr,yl,yr>=0,sum可正可负。

    对于统一,记一个sa标志,表示该子树所有元素都变为这一个。

    对于翻转,记一个rev标志,表示该子树是否翻转。

    对于改变,记一个en标志,表示该子树是否改变。

    并且三者都需要下传标记。下传时s,xl,xr,yl,yr,sum都需维护。统一比较简单,翻转要交换xl和xr,yl和yr,改变要交换xl和yl,xr和yr。而rev还需将左右子树对换(序列的顺序改变)。

    每次对于提取区间(a,b),分情况讨论。

    1、整个区间——区间对应为根

    2、(1,x)——x+1旋到根,区间对应为根的左子树

    3、(x,n)——x-1旋到根,区间对应为根的右子树

    4、(x,y)——x-1旋到根,接着y+1旋到根的右子树,区间对应为根的右子树的左子树

    每次操作提取出来区间对应的子树节点后进行操作,并将到根的路径上的节点再维护一下。

    问题到这似乎已经完美解决了。

    但是,我们要注意到一个极其棘手的问题,如果一个节点同时存在统一,翻转,改变,先传哪一个?首先,翻转是没有问题的,先翻转再统一,或先统一再翻转都一样,先翻转再改变,或先改变再翻转也都一样,我们不妨把它的顺序放在第一位。然而先统一再改变与先改变再统一却会出问题的,两者会有不一样的结果,到底哪个在前?只能视标记的最初时间而定。统一的时间早则先统一,否则先改变。于是我们马上想到记录一个标记时间,下传时,将标记时间一同下传即可。但是这样做仍是会出问题的。为什么?

    我们对一个节点(开始什么标记也没有)进行三次操作(假设中间不下传):改变,统一,改变。那么我们会发现,原本我们记录的boolean类型的en两次操作后变成了false,而统一符号仍然在,我们下次要下传时,子树的标记就完全不对了。为什么?因为我们之前考虑的是两次改变等价于没改,但是如果中间有统一标志,那么其实就是不等价了。

    解决这一问题的方法可以是,先把改变放在前,统一放在后。那么我们只需特判一种情况:先统一,再改变,而这种情况出现的条件是在先改变下传标记时,有统一标记且统一标记的时间比当前改变下传标记早,那么我们就只需将改变记为false,将统一变为其相反数,并维护即可。也即强制使统一标记的时间大于改变下传标记时间。至此问题解决的主要过程已清晰可见了。

    空间复杂度O(N)。建树O(N),单次询问O(logN),总时间复杂度O(N+MlogN)。

    const
    	maxn=100000;
    var
    	n,m,i,j,k,p,x,y,root,tmp:longint;c:char;str:string;
    	rev,en:array[0..maxn] of boolean;
    	l,r,fa,sum,s,size,sa,xl,xr,yl,yr,satime,entime:array[0..maxn] of longint;
    function reads:string;
    begin
    	reads:='';
    	repeat
    		read(c);
    		if c=' ' then break;
    		reads:=reads+c;
    	until eoln;
    end;
    
    function readn:longint;
    begin
    	readn:=0;
    	repeat
    		read(c);
    		if c=' ' then break;
    		readn:=readn*10+ord(c)-ord('0');
    	until eoln;
    end;
    function max(a,b:longint):longint;
    begin
    	if a>b then exit(a) else exit(b);
    end;
    procedure prev(i:longint);
    begin
    	rev[i]:=not rev[i];
    	tmp:=xl[i];xl[i]:=xr[i];xr[i]:=tmp;
    	tmp:=yl[i];yl[i]:=yr[i];yr[i]:=tmp;
    	tmp:=l[i];l[i]:=r[i];r[i]:=tmp;
    end;
    procedure psa(i,t,time:longint);
    begin
        satime[i]:=time;
        sa[i]:=t;
    	s[i]:=t;
    	sum[i]:=t*size[i];
    	if t=1 then begin xl[i]:=sum[i];xr[i]:=sum[i];yl[i]:=0;yr[i]:=0;end
    	else begin xl[i]:=0;xr[i]:=0;yl[i]:=-sum[i];yr[i]:=-sum[i];end;
    end;
    
    procedure pen(i,time:longint);
    begin
    	if (satime[i]>0)and(satime[i]<time) then
        begin
    		en[i]:=false;
            psa(i,-sa[i],time);
            exit;
       end;
    
            entime[i]:=time;
            en[i]:=not en[i];
        s[i]:=-s[i];
        sum[i]:=-sum[i];
    	tmp:=xl[i];xl[i]:=yl[i];yl[i]:=tmp;
    	tmp:=xr[i];xr[i]:=yr[i];yr[i]:=tmp;
    end;
    
    procedure pup(i:longint);
    begin
    	size[i]:=size[l[i]]+size[r[i]]+1;
    	sum[i]:=sum[l[i]]+sum[r[i]]+s[i];
    	xl[i]:=max(max(xl[l[i]],sum[l[i]]+s[i]+xl[r[i]]),0);
    	xr[i]:=max(max(xr[r[i]],sum[r[i]]+s[i]+xr[l[i]]),0);
    	yl[i]:=max(max(yl[l[i]],-sum[l[i]]-s[i]+yl[r[i]]),0);
    	yr[i]:=max(max(yr[r[i]],-sum[r[i]]-s[i]+yr[l[i]]),0);
    end;
    procedure pdown(i:longint);
    begin
        if rev[i] then
        begin
    		if l[i]>0 then prev(l[i]);
    		if r[i]>0 then prev(r[i]);
    		rev[i]:=false;
        end;
    
         if en[i] then
         begin
    		pen(l[i],entime[i]);
            pen(r[i],entime[i]);
    		en[i]:=false;
    		entime[i]:=0;
         end;
    
        if sa[i]<>0 then
    	begin
    		if l[i]>0 then psa(l[i],sa[i],satime[i]);
    		if r[i]>0 then psa(r[i],sa[i],satime[i]);
    		sa[i]:=0;
    		satime[i]:=0;
    	end;
    end;
    procedure left(i:longint);
    var x,y:longint;
    begin
    	x:=r[i];
    	y:=l[x];
    	r[i]:=y;
    	if y>0 then fa[y]:=i;
    	if fa[i]>0 then
    		if l[fa[i]]=i then l[fa[i]]:=x else r[fa[i]]:=x;
    	fa[x]:=fa[i];
    	l[x]:=i;
    	fa[i]:=x;
    	pup(i);
    	if i=root then root:=x;
    end;
    
    procedure right(i:longint);
    var x,y:longint;
    begin
    	x:=l[i];
    	y:=r[x];
    	l[i]:=y;
    	if y>0 then fa[y]:=i;
    	if fa[i]>0 then
    		if l[fa[i]]=i then l[fa[i]]:=x else r[fa[i]]:=x;
    	fa[x]:=fa[i];
    	r[x]:=i;
    	fa[i]:=x;
    	pup(i);
    	if i=root then root:=x;
    end;
    
    procedure splay(x,f:longint);
    var y,z:longint;
    begin
    	pdown(x);
    	while fa[x]<>f do
    	begin
    		y:=fa[x];
    		z:=fa[y];
                    if z>0 then pdown(z);
                    if y>0 then pdown(y);
    		if z=f then
    			if l[y]=x then right(y) else left(y)
    			else
    			if l[z]=y then
    				if l[y]=x then begin right(z);right(y);end
    						  else begin left(y);right(z);end
    					  else
    				if l[y]=x then begin right(y);left(z);end
    						  else begin left(z);left(y);end;
            end;
            pup(x);
    end;
    
    procedure sel(x,f:longint);
    var t:longint;
    begin
    	t:=root;
    	repeat
    		pdown(t);
    		if x=size[l[t]]+1 then break
    		else
    		if x<size[l[t]]+1 then t:=l[t]
    		else begin dec(x,size[l[t]]+1);t:=r[t];end;
    	until false;
    	splay(t,f);
    end;
    
    function tiqu(x,y:longint):longint;
    begin
    	if x=1 then
    		if y=n then exit(root)
    			   else begin sel(y+1,0);exit(l[root]);end
    		   else
    	if y=n then begin sel(x-1,0);exit(r[root]);end
    		   else begin sel(x-1,0);sel(y+1,root);exit(l[r[root]]);end;
    end;
    
    procedure build(x,y,f,t:longint);
    begin
    	if f=0 then root:=(x+y) div 2
    	else
    	if t=0 then l[f]:=(x+y) div 2 else r[f]:=(x+y) div 2;
    	fa[(x+y) div 2]:=f;
    	if x<=(x+y) div 2-1 then build(x,(x+y) div 2-1,(x+y) div 2,0);
    	if (x+y) div 2+1<=y then build((x+y) div 2+1,y,(x+y) div 2,1);
    	pup((x+y) div 2);
    end;
    
    procedure print(i:longint);
    begin
            pdown(i);
            if l[i]>0 then print(l[i]);
            if s[i]=1 then write('(') else write(')');
            if r[i]>0 then print(r[i]);
            pup(i);
    end;
    function check:boolean;
    var i:longint;
    begin
            for i:=1 to n do
            if (xl[i]<0)or(xr[i]<0)or(yl[i]<0)or(yr[i]<0) then exit(false);
            exit(true);
    end;
    
    begin
    		assign(input,'Brackets.in');
    		assign(output,'Brackets.out');
    		reset(input);rewrite(output);
    
    		readln(n,m);
    		for i:=1 to n do
    		begin
    			read(c);
    			if c='(' then s[i]:=1 else s[i]:=-1;
    		end;
    		readln;
    
    		build(1,n,0,0);
    
    		for i:=1 to m do
    		begin
    			str:=reads;
    			x:=readn;
    			y:=readn;
    			p:=tiqu(x,y);
    			if str='Query' then
    			begin
    				writeln((yl[p]+1) div 2+(xr[p]+1) div 2);
    			end
    			else
    			if str='Replace' then
    			begin
    				read(c);
    				if c='(' then psa(p,1,i) else psa(p,-1,i);
    				while fa[p]>0 do begin pup(fa[p]);p:=fa[p];end;
    			end
    			else
    			if str='Swap' then
    			begin
    				prev(p);
    				while fa[p]>0 do begin pup(fa[p]);p:=fa[p];end;
    			end
    			else
    			if str='Invert' then
    			begin
                    pen(p,i);
    				while fa[p]>0 do begin pup(fa[p]);p:=fa[p];end;
    			end;
    			readln;
    
                //print(root);
                //writeln;
                //if not check then writeln('no');
    		end;
            close(input);close(output);
    end.
    
  • 相关阅读:
    ssh 免密码登陆设置不成功
    mysql: SOURCE error 2?
    Debug --> 服务器上运行代码的not find module错误
    Debug --> 使用服务器的一些日常记录
    Debug --> 使用pycharm(pro)部署项目至服务器
    Debug --> python 将输出至控制台的信息存入指定txt文件
    Debug --> matlibplot的字体设置方法
    Machine Learning --> MSE&RMSE&MAE
    Debug --> 奇奇怪怪的显卡调用错误
    Debug --> Variable,Tensor,Numpy的转换
  • 原文地址:https://www.cnblogs.com/oldmanren/p/2262178.html
Copyright © 2011-2022 走看看