括号树
Get up where you tripped over.
做一做CSPS2019,感受一下自己当时的愚蠢现在的愚蠢。
很喜欢skyh的一句话:勇争第二吧,祝福你们。
2019年11月16日上午9时许,我大概觉得想到了T2正解,于是开码,发现算法自身bug,GG等死
2021年11月16日上午9时许,我大概觉得我又行了(不是),于是继续想T2,发现我是真的很愚蠢。
我来陈述一下我的误区,大概是dfs到一个节点,现在就考虑从根到这个节点x有多少以x为结尾的括号序列。
我当时的想法是,首先可以考虑前缀和为0,也就是查找从根到路径上的点i,使得sum[i]=sum[x],加上一个限制,就是从i到x上的所有点不能有sumj<sumi,防止出现“)(”这种情况
实际上我的思路就是很不清晰的,也和没有逻辑,我应该考虑合法括号序列的等价条件是什么。当时觉得如果一个满足前缀和条件的sumi不能满足第二个限制,那么前面的点也不能满足,有一个单调性
于是我就开始大力yy,想能不能查找得点都满足在一个点之后,然后我发现错了,然后就GG了
但是这个思路是可以修正的,考虑事情一定要考虑清楚,把他的等价条件摆清楚,摆着摆着就会了
现在就是一个点很小,所有在他之前的比他大的点都不能跨过他作为左端点,那就很明显是单调栈的思想,也就是这个很小的点弹掉了之前那些比他大的点,维护一个关于sum的单调栈从根节点到目前的x,除此之外,我现在要建立一个数据结构,要统计一个权值sum等于sumx的个数,我可以有log复杂度查询,那我现在就可以使用主席树,但是有些点是不行的,我可以直接跳过这些点建树,也就是说,我维护一个从根节点到x的主席树,方便我跳过某些版本来建树,跳过的那些版本对应的就是我单调栈内被弹掉的元素,剩下的都是一定能够作为左端点的元素,然后再查询这个集合里有sumx=sumi的个数,就行了。
尽管不是最优的,但是出题人不是放了么
也不是说这个做法有多好,只是有些坎过不去而已。
#include<iostream> #include<cstdio> #include<vector> using namespace std; const int N=5e5+9; char s[N]; int a[N],sum[N],pr[N],fa[N],rt[N],n,tt,root; long long f[N]; vector<int>ve[N]; struct tree { int w,lc,rc; }tr[N*30]; int rd() { int s=0,w=1; char cc=getchar(); for(;cc<'0'||cc>'9';cc=getchar()) if(cc=='-') w=-1; for(;cc>='0'&&cc<='9';cc=getchar()) s=(s<<3)+(s<<1)+cc-'0'; return s*w; } void insert(int &k,int p,int l,int r,int w) { k=++tt; tr[k]=tr[p]; if(l==r){tr[k].w++;return;} int mid=(l+r)>>1; if(w<=mid) insert(tr[k].lc,tr[p].lc,l,mid,w); else insert(tr[k].rc,tr[p].rc,mid+1,r,w); tr[k].w=tr[tr[k].lc].w+tr[tr[k].rc].w; } int askp(int k,int l,int r,int w) { if(l==r) return tr[k].w; int mid=l+r>>1; if(w<=mid) return askp(tr[k].lc,l,mid,w); else return askp(tr[k].rc,mid+1,r,w); } void dfs1(int x) { sum[x]=sum[fa[x]]+a[x]; int now=fa[x]; while(now&&sum[x]<sum[now]) now=pr[now]; if(now==0&&sum[x]<0)pr[x]=-1; else pr[x]=now; if(pr[x]>=0)insert(rt[x],rt[pr[x]],-n,n,sum[x]); else insert(rt[x],root,-n,n,sum[x]); if(a[x]==1) f[x]=f[fa[x]]; else f[x]=f[fa[x]]+askp(rt[x],-n,n,sum[x])-1; for(int i=0;i<ve[x].size();i++) { int y=ve[x][i]; if(y==fa[x]) continue; dfs1(y); } } int main() { freopen("brackets.in","r",stdin); freopen("brackets.out","w",stdout); n=rd();root=tt++; scanf("%s",s+1); for(int i=1;i<=n;i++) { if(s[i]=='(') a[i]=1; else a[i]=-1; } for(int i=2;i<=n;i++) { fa[i]=rd(); ve[fa[i]].push_back(i); } insert(rt[0],root,-n,n,0); dfs1(1); long long ans=0; for(int i=1;i<=n;i++)ans^=(1ll*i*f[i]); printf("%lld\n",ans); } /* d: g++ 1.cpp -o 1 1.exe 50 ))()(())((((()))))))((())))()))((()(()((((((())()) 1 2 1 2 2 6 6 6 6 10 10 10 7 13 13 10 13 15 18 18 20 17 19 10 25 26 27 25 25 25 31 29 30 34 25 34 29 25 30 39 38 41 34 36 35 43 44 25 44 */