1. 程式人生 > >HNOI2011 括號修復

HNOI2011 括號修復

題目描述

題解:

首先,任意一個括號序列消去成對括號後一定是‘)))……)(……(((’的形式。

如果我們能求出當前子序列消去後剩下的東西長什麼樣,我們就能O(1)出解。

比如前面有a個')',後面有b個‘(’。

那麼$ans = (a+1)/2 + (b+1)/2$.

建議自己畫一畫。

現在的問題是怎麼修改。

splay支援區間翻轉,考慮用splay維護。

這裡引入我的構造想法,不知道有沒有人用:

將')''('分別作為:

這樣串))(((((())可表示為:

我們可以發現,剩餘的')'就是正向看的最大向上高度,'('就是反向看的最大向下高度

所以我們要維護這兩個值。

這樣replace和swap操作可以解決。

那麼invert呢?

就是讓這個圖形上下倒過來畫咯。

所以我們還要維護最小向上/向下高度。

所以總結一下:

swap:交換兩個最大、交換兩個最小;

invert:交換兩個正向看的值並變成相反數、交換兩個反向看的值並變成相反數;

replace:區間賦值,重要的是清invert標記!!!

然後程式碼:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 100050
int n,m;
char s[N]; struct Splay { int fa[N],ch[N][2],siz[N],rt,rep[N]; bool swa[N],inr[N]; int v[N],f[N][2],g[N][2],tag[N],sum[N];//max/min front max/min back void update(int u) { int ls = ch[u][0],rs = ch[u][1]; siz[u] = siz[ls]+siz[rs]+1; sum[u] = sum[ls]+sum[rs]+v[u]; f[u][
0] = max(f[ls][0],sum[ls]+v[u]+f[rs][0]); f[u][1] = min(f[ls][1],sum[ls]+v[u]+f[rs][1]); g[u][0] = max(g[rs][0],sum[rs]+v[u]+g[ls][0]); g[u][1] = min(g[rs][1],sum[rs]+v[u]+g[ls][1]); } void Swap(int u) { if(!u)return ; swa[u]^=1; swap(ch[u][0],ch[u][1]); swap(f[u][0],g[u][0]); swap(f[u][1],g[u][1]); } void Inr(int u) { if(!u)return ; inr[u]^=1; v[u]=-v[u];sum[u]=-sum[u]; swap(f[u][0],f[u][1]); swap(g[u][0],g[u][1]); f[u][0]=-f[u][0];f[u][1]=-f[u][1]; g[u][0]=-g[u][0];g[u][1]=-g[u][1]; } void Rep(int u,int d) { if(!u)return ; tag[u]=d; inr[u]=0; v[u]=d; if(d==1) { sum[u]=siz[u]; f[u][0]=g[u][0]=siz[u]; f[u][1]=g[u][1]=0; }else { sum[u]=-siz[u]; f[u][0]=g[u][0]=0; f[u][1]=g[u][1]=-siz[u]; } } void pushdown(int u) { int ls = ch[u][0],rs = ch[u][1]; if(tag[u]) { Rep(ls,tag[u]),Rep(rs,tag[u]); tag[u]=0;swa[u]=0; } if(swa[u]) { Swap(ls),Swap(rs); swa[u]=0; } if(inr[u]) { Inr(ls),Inr(rs); inr[u]=0; } } int st[N],tl; void down(int u) { tl=0;st[++tl]=u; while(fa[u])u=fa[u],st[++tl]=u; while(tl)pushdown(st[tl]),tl--; } void rotate(int x) { int y = fa[x],z = fa[y],k = (ch[y][1]==x); ch[y][k]=ch[x][!k],fa[ch[x][!k]]=y; ch[x][!k]=y,fa[y]=x; ch[z][ch[z][1]==y]=x,fa[x]=z; update(y),update(x); } void splay(int x,int goal) { down(x); while(fa[x]!=goal) { int y = fa[x],z = fa[y]; if(z!=goal) (ch[z][1]==y)^(ch[y][1]==x)?rotate(x):rotate(y); rotate(x); } if(!goal)rt = x; } int get_pnt(int x,int k) { pushdown(x); int tmp = siz[ch[x][0]]; if(k<=tmp)return get_pnt(ch[x][0],k); else if(k==tmp+1)return x; return get_pnt(ch[x][1],k-tmp-1); } int build(int l,int r,int f) { if(l>r)return 0; int x = (l+r)>>1; fa[x] = f; v[x] = (s[x]=='('?-1:1); ch[x][0] = build(l,x-1,x); ch[x][1] = build(x+1,r,x); update(x); return x; } void split(int &x,int &y) { x = get_pnt(rt,x); y = get_pnt(rt,y+2); splay(x,0);splay(y,x); } void _replace(int x,int y,int d) { split(x,y); Rep(ch[y][0],d); update(y),update(x); } void _swap(int x,int y) { split(x,y); Swap(ch[y][0]); update(y),update(x); } void _invert(int x,int y) { split(x,y); Inr(ch[y][0]); update(y),update(x); } int _query(int x,int y) { split(x,y); return (f[ch[y][0]][0]+1)/2+(-g[ch[y][0]][1]+1)/2; } }tr; char opt[20]; int main() { scanf("%d%d%s",&n,&m,s+2); tr.rt=tr.build(1,n+2,0); for(int x,y,i=1;i<=m;i++) { scanf("%s%d%d",opt+1,&x,&y); if(opt[1]=='R') { scanf("%s",opt+1); int d = 1; if(opt[1]=='(')d=-1; tr._replace(x,y,d); }else if(opt[1]=='S') { tr._swap(x,y); }else if(opt[1]=='I') { tr._invert(x,y); }else { printf("%d\n",tr._query(x,y)); } } return 0; }