Description
Input
Output
输出到文件 brackets.out 中。
仅一行一个整数表示答案。
Sample Input
5
(()()
1 1 2 2
Sample Output
6
Data Constraint
Solution
树上括号问题,题目大意是:给你一棵树,让你求对于每一个点,从根节点到这个点的连续子序列为合法括号序的数量的总和。
不会正解。
只打了个n^2+n log n 的解法,比赛后才发现不用那个log,直接n^2。
枚举节点,直接计算上面的答案加上以这个点为结尾的合法括号序的答案即可。
至于正解,先设g[i]表示 i 以这个点为结尾能往前找到的合法括号序的个数,那么每次我们找到最深的一个点使得这个点到当前dg到的x这一段括号序是合法的(即前缀和a[x]==a[y]),那么这个点x的答案可以由找到的点y的父亲的g值+1转移过来,因为上一段是合法的接上这一段合法的括号序仍然是合法的,+1是y~x这一段括号序。
因此可以用倍增维护从当前这个点到上面的区间最小值。
当a[x]小于等于倍增跳到的点时就可以结束了,因为等于时找到了y,而小于时则是不合法的括号序。
第二种方法则是设last[x]表示从根节点到x中深度最深的没有匹配过的左括号的编号,当dfs到的这个点是左括号是,它的last就是它自己,而是右括号时,它就可以用它与它父亲的last匹配,那么它的last就是它父亲的last的父亲的last。
这样就直接建立了递推关系直接进行递推。
Code1
#include<cstdio>
#include<cstring>
#include<algorithm>
#define I int
#define ll long long
#define F(i,a,b) for(I i=a;i<=b;i++)
#define Fd(i,a,b) for(I i=a;i>=b;i--)
#define mem(a,b) memset(a,b,sizeof(a))
#define N 1000010
using namespace std;
I n,x,t[N*2],nx[N*2],l[N],a[N],tot;
I s[N][20],f[N][20],d[N*2],bz[N];
ll ans,g[N];
char ch;
void add(I x,I y){t[++tot]=y;nx[tot]=l[x];l[x]=tot;}
void rd(I &x){
x=0;ch=getchar();
while(ch<'0'||ch>'9') ch=getchar();
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
}
void dfs(I x,I y){
mem(bz,0);
I i=1,j=1;d[1]=1;bz[1]=1;
while(i<=j){
x=d[i++];
for(I k=l[x];k;k=nx[k]) if(!bz[t[k]]){
bz[t[k]]=1;
d[++j]=t[k];
f[t[k]][0]=x;s[t[k]][0]=a[x];
a[t[k]]+=a[x];
}
}
}
void dg(I x,I y){
mem(bz,0);
I he=1,ta=1;d[1]=1;bz[1]=1;
while(he<=ta){
I x=d[he++],z=x;
Fd(i,19,0){
if(s[z][i]>a[x]) z=f[z][i];
}
if(a[f[z][0]]==a[x]){
g[x]+=g[f[z][0]]-g[f[f[z][0]][0]]+1;
}
for(I k=l[x];k;k=nx[k]) if(!bz[t[k]]){
bz[t[k]]=1;
d[++ta]=t[k];
g[t[k]]+=g[x];
}
}
}
I main(){
freopen("brackets.in","r",stdin);
freopen("brackets.out","w",stdout);
rd(n);
F(i,1,n){
ch=getchar();
while(ch!=')'&&ch!='(') ch=getchar();
if(ch=='(') a[i]=1;
else a[i]=-1;
}
F(i,2,n){
rd(x);
add(x,i);
add(i,x);
}
dfs(1,0);
F(j,1,19){
F(i,1,n){
f[i][j]=f[f[i][j-1]][j-1];
s[i][j]=min(s[i][j-1],s[f[i][j-1]][j-1]);
}
}
dg(1,0);
F(i,1,n) ans^=(i*g[i]);
printf("%lld\n",ans);
return 0;
}
Code2
#include<cstdio>
#include<cstring>
#include<algorithm>
#define I int
#define ll long long
#define F(i,a,b) for(I i=a;i<=b;i++)
#define Fd(i,a,b) for(I i=a;i>=b;i--)
#define mem(a,b) memset(a,b,sizeof(a))
#define N 1000010
using namespace std;
I n,x,t[N*2],nx[N*2],l[N],a[N],s[N],tot,f[N],p,fa[N];
ll ans,g[N];
char ch;
void add(I x,I y){t[++tot]=y;nx[tot]=l[x];l[x]=tot;}
void rd(I &x){
x=0;ch=getchar();
while(ch<'0'||ch>'9') ch=getchar();
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
}
void dg(I x,I y){
s[x]=a[x]+s[y];g[x]+=g[y];
if(a[x]==1) f[x]=x;
else{
p=f[y];
if(p) g[x]+=g[fa[p]]-g[fa[fa[p]]]+1;
f[x]=f[fa[p]];
}
ans^=(x*g[x]);
for(I k=l[x];k;k=nx[k]){
if(t[k]!=y){
dg(t[k],x);
}
}
}
I main(){
freopen("brackets.in","r",stdin);
freopen("brackets.out","w",stdout);
rd(n);
F(i,1,n){
ch=getchar();
while(ch!=')'&&ch!='(') ch=getchar();
a[i]=ch=='('?1:-1;
}
F(i,2,n){rd(x);fa[i]=x;add(x,i);add(i,x);}
dg(1,0);
printf("%lld\n",ans);
return 0;
}
作者:zsjzliziyang
QQ:1634151125
转载及修改请注明
本文地址:https://blog.csdn.net/zsjzliziyang/article/details/103321788