括号树

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

*/

  

 

posted @ 2021-11-28 11:30  starsing  阅读(112)  评论(3编辑  收藏  举报