求區間最長匹配的括號序列子串。
很有意思的括號,但是我有些細節沒處理好,導致代碼長,算法複雜。。 如果有更好的算法我也很想知道啊>.<
考慮一個括號序列A=(B1)(B2)(B3)…,其中與某個括號匹配的相對的括號唯一。證明顯然。
有一個顯然的算法:用棧判斷一個字符串是否爲括號序列。
考慮拓展這個結論:對任意括號串的某個括號序列子串,某個括號匹配的相對的括號唯一。證明顯然。
既然這樣就隨便建一些()樹,每個節點表示一對匹配的括號,兒子表示在這對括號中的括號序列。
不妨只考慮詢問在同一顆()樹的(節點~)節點的答案。
如圖,詢問綠括號的答案,令u,v是深度大於lca的最淺的x,y的祖先。那麼(u,v)這一段都可以作爲答案。對於答案不在這之中的情況,考慮選綠括號和不選綠括號。
選的方案容易得到,不選的方案相當於鏈上最大值。於是可以在O(nlogn+qlogn)的時間內得到答案。
如果是長鏈剖分可以達到O(nlogn+q)的毒瘤複雜度。
算法瓶頸在於尋找uv,不知道有沒有更好的做法。
這裏有claris的題解
似乎這種括號匹配還能離線做,可以思考一下,想出來再更新吧。。
#include<bits/stdc++.h>
#define N 400005
using namespace std;
int n,q,id[N],l[N],r[N],lt[N],rt[N],fl[N],fr[N];
int Rt[N],ly,f[N];
int fa[N][25],dep[N],v[N][25],vl[N][25],vr[N][25],cnt;
int st[N],top;
char s[N];
void build(int k,int L,int R)
{
for (int i=2,j=1;i<=dep[k];i<<=1,j++)
{
fa[k][j]=fa[fa[k][j-1]][j-1];
vl[k][j]=max(vl[k][j-1],vl[fa[k][j-1]][j-1]);
vr[k][j]=max(vr[k][j-1],vr[fa[k][j-1]][j-1]);
}
if (L>R) return;
int t=L;
for (;L<=R;L=r[L]+1)
{
fa[++cnt][0]=k;
dep[cnt]=dep[k]+1;
f[cnt]=f[k];
vl[cnt][0]=R-r[L];
vr[cnt][0]=L-t;
id[L]=cnt;id[r[L]]=cnt;
lt[cnt]=L;
rt[cnt]=r[L];
build(cnt,L+1,r[L]-1);
}
}
int lg[N];
int qry(int x,int y)
{
if (x>y) return 0;
int len=y-x+1,tmp=lg[len];
return max(v[x][tmp],v[y-(1<<tmp)+1][tmp]);
}
int main()
{
scanf("%d%d",&n,&q);
scanf("%s",s+1);
for (int i=1;i<=n;i++)
{
if (s[i]==')')
{
if (top)
{
l[i]=st[top];
r[st[top--]]=i;
}
}
else st[++top]=i;
}
for (int i=1;i<=n;i++)
{
if (r[i])
{
int tmp=r[i];
for (;r[tmp+1];tmp=r[tmp+1]);
Rt[++ly]=++cnt;
f[cnt]=ly;v[ly][0]=tmp-i+1;
lt[cnt]=i-1;rt[cnt]=tmp+1;
build(cnt,i,tmp);
i=tmp;
}
}
lg[1]=0;
for (int i=2;i<=ly;i++)
lg[i]=lg[i>>1]+1;
for (int i=1;i<=lg[ly];i++)
for (int j=1;j<=n-(1<<i)+1;j++)
{
v[j][i]=max(v[j][i-1],v[j+(1<<i-1)][i-1]);
}
for (int i=1,t=0;i<=n;i++)
{
if (l[i]) t=i;
fl[i]=t;
}
for (int i=n,t=n+1;i>=1;i--)
{
if (r[i]) t=i;
fr[i]=t;
}
for (int i=1;i<=q;i++)
{
int x,y;
scanf("%d%d",&x,&y);
x=fr[x];
y=fl[y];
if (x>y) puts("0");
else
{
int t1,t2,Ans=0;
if (id[x]==id[y]) Ans=y-x+1;
else
{
x=id[x];y=id[y];
if (f[x]==f[y])
{
if (dep[x]>dep[y])
{
Ans=max(Ans,rt[fa[x][0]]-lt[x]);
t1=1<<20;t2=20;
for (;t2>=0;t1>>=1,t2--)
{
if (t1>dep[x]-dep[y])continue;
Ans=max(Ans,vl[x][t2]);
x=fa[x][t2];
}
Ans=max(Ans,rt[y]-max(lt[fa[y][0]],rt[x]));
}
else if (dep[x]<dep[y])
{
Ans=max(Ans,rt[y]-lt[fa[y][0]]);
t1=1<<20;t2=20;
for (;t2>=0;t1>>=1,t2--)
{
if (t1>dep[y]-dep[x])continue;
Ans=max(Ans,vr[y][t2]);
y=fa[y][t2];
}
Ans=max(Ans,min(rt[fa[x][0]],lt[y])-lt[x]);
}
else
{
Ans=max(Ans,rt[y]-max(lt[fa[y][0]],lt[x]-1));
Ans=max(Ans,min(rt[fa[x][0]],rt[y]+1)-lt[x]);
}
t1=1<<20;t2=20;
for (;t2>=0;t1>>=1,t2--)
{
if (t1>dep[x]||fa[x][t2]==fa[y][t2])continue;
Ans=max(Ans,vl[x][t2]);
Ans=max(Ans,vr[y][t2]);
x=fa[x][t2];
y=fa[y][t2];
}
Ans=max(Ans,lt[y]-rt[x]-1);
}
else
{
Ans=max(Ans,rt[fa[x][0]]-lt[x]);
Ans=max(Ans,rt[y]-lt[fa[y][0]]);
t1=1<<20;t2=20;
for (;t2>=0;t1>>=1,t2--)
{
if (t1>dep[x])continue;
Ans=max(Ans,vl[x][t2]);
x=fa[x][t2];
}
t1=1<<20;t2=20;
for (;t2>=0;t1>>=1,t2--)
{
if (t1>dep[y])continue;
Ans=max(Ans,vr[y][t2]);
y=fa[y][t2];
}
Ans=max(Ans,qry(f[x]+1,f[y]-1));
}
}
printf("%d\n",Ans);
}
}
}