第十二届蓝桥杯国赛括号线段树
Posted 爷灬傲奈我何123
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第十二届蓝桥杯国赛括号线段树相关的知识,希望对你有一定的参考价值。
题面:
题意:
操作1 把区间括号翻转
操作2 查询最长合法括号序列序列从l开始
思路:
类似于区间合并的问题,对于每个区间我们记录左右最小最大前缀值,我们把(看作1,)看作-1,合法的括号序列满足于当前的sum=0且对于任意前缀都是>=0,那么满足二分性质,我们可以二分套线段树查询到从l开始满足前缀大于等于0的最大位置,然后如果下个位置的sum<0那么就是当前位置,但是会有可能是查询到n,然后后面没数了且sum>0,那么我们就要二分出第一个后缀最大值等于sum的位置。
调了一下午调的心累。。。
代码:
#include<bits/stdc++.h>
#define IL inline
#define x first
#define y second
typedef long long ll;
using namespace std;
const int N=200010;
struct node{
int l;
int r;
int lz;
int sum;
int lmax;
int lmin;
int rmax;
int rmin;
}tr[N<<2];
string s;
int n;
int m;
void pushup(int u)
{
tr[u].sum=tr[u<<1].sum+tr[u<<1|1].sum;
tr[u].lmax=max(tr[u<<1].lmax,tr[u<<1|1].lmax+tr[u<<1].sum);
tr[u].lmin=min(tr[u<<1].lmin,tr[u<<1].sum+tr[u<<1|1].lmin);
tr[u].rmin=min(tr[u<<1|1].rmin,tr[u<<1|1].sum+tr[u<<1].rmin);
tr[u].rmax=max(tr[u<<1|1].rmax,tr[u<<1|1].sum+tr[u<<1].rmax);
}
void update(node &u)
{
swap(u.lmin,u.lmax);
u.lmin*=-1;
u.lmax*=-1;
u.sum=-u.sum;
swap(u.rmin,u.rmax);
u.rmin*=-1;
u.rmax*=-1;
}
void pushdown(int u)
{
if(tr[u].lz)
{
tr[u<<1].lz^=1;
tr[u<<1|1].lz^=1;
update(tr[u<<1]);
update(tr[u<<1|1]);
tr[u].lz=0;
}
}
void build(int u,int l,int r)
{
tr[u]={l,r};
if(l==r)
{
if(s[l]==')')
{
tr[u].sum=-1;
tr[u].lmax=tr[u].lmin=-1;
tr[u].rmax=tr[u].rmin=-1;
}
else
{
tr[u].sum=1;
tr[u].lmax=tr[u].lmin=1;
tr[u].rmax=tr[u].rmin=1;
}
return;
}
int mid=l+r>>1;
build(u<<1,l,mid);
build(u<<1|1,mid+1,r);
pushup(u);
}
void mdf(int u,int l,int r)
{
if(tr[u].l>=l && tr[u].r<=r)
{
tr[u].lz^=1;
update(tr[u]);
return ;
}
pushdown(u);
int mid=tr[u].l+tr[u].r>>1;
if(l<=mid)
mdf(u<<1,l,r);
if(r>mid)
mdf(u<<1|1,l,r);
pushup(u);
}
int querysum(int u,int l,int r)
{
if(tr[u].l>=l && tr[u].r<=r)
return tr[u].sum;
pushdown(u);
int mid=tr[u].l+tr[u].r>>1;
int sum=0;
if(l<=mid) sum+=querysum(u<<1,l,r);
if(r>mid) sum+=querysum(u<<1|1,l,r);
return sum;
}
int querymax(int u,int l,int r)
{
if(tr[u].l>=l && tr[u].r<=r)
return tr[u].rmax;
pushdown(u);
int mid=tr[u].l+tr[u].r>>1;
int maxv=0;
if(r<=mid) return querymax(u<<1,l,r);
else if(l>mid) return querymax(u<<1|1,l,r);
else
{
int dd=querysum(u<<1|1,l,r);
int td=querymax(u<<1,l,r);
int td2=querymax(u<<1|1,l,r);
return max(td2,td+dd);
}
}
int query(int u,int l,int r)
{
if(tr[u].l>=l && tr[u].r<=r)
return tr[u].lmin;
pushdown(u);
int mid=tr[u].l+tr[u].r>>1;
if(r<=mid)
return query(u<<1,l,r);
else if(l>=mid+1)
return query(u<<1|1,l,r);
else
{
int a=query(u<<1,l,r);
int b=query(u<<1|1,l,r);
return min(a,querysum(u<<1,l,r)+b);
}
}
int main()
{
cin >> n >> m;
cin >> s;
s = " "+s;
build(1,1,n);
//cout<<query(1,2,7)<<endl;
//cout<<query(1,3,4)<<endl;
while(m--)
{
int op;
cin >> op;
if(op==2)
{
int x;
cin >> x;
int l=x,r=n;
// if(x==6)
// cout<<"!"<<query(1,6,7)<<endl;
int ans=0;
while(l<r)
{
int mid=l+r+1>>1;
// cout<<query(1,x,mid)<<endl;
if(query(1,x,mid)>=0) l=mid;
else r=mid-1;
}
int tt=query(1,x,l);
//cout<<" ->"<<l<<" "<<tt<<endl;
int ansl=l;
int sum=querysum(1,x,n);
if(tt!=0)
{
cout<<0<<endl;
continue;
}
if(ansl==n && sum)
{
//cout<<"--"<<endl;
l=x;
r=n;
while(l<r)
{
int mid=l+r+1>>1;
if(querymax(1,mid,n)>=sum) l=mid;
else r=mid-1;
}
cout<<r-1<<endl;
}
else
cout<<l<<endl;
}
else
{
int l,r;
cin >> l >> r;
mdf(1,l,r);
}
// for(int j=1;j<=n;j++)
// if(query(1,j,j)==1)
// cout<<"(";
// else if(query(1,j,j)==-1)
// cout<<")";
// cout<<endl;
}
return 0;
}
/*
7 5
((())()
2 3
2 2
1 3 5
2 3
2 1
3
4
(((
2 3
1 2 3
1 1 2
2 2
8
9
)(((((((
1 2 4
1 3 4
2 1
1 5 5
1 7 7
1 3 6
1 4 6
2 6
2 1
12
6
())((()()()(
2 6
1 1 8
1 7 11
2 2
1 3 8
2 10
*/
以上是关于第十二届蓝桥杯国赛括号线段树的主要内容,如果未能解决你的问题,请参考以下文章