100%的数据满足N,Q不超过10^5
。
第一轮
题解:splay
我们将括号序列改成-1与1的序列,用-1表示(,用1表示)。
那么一段区间中前缀和的最大值就是未匹配的)的数量(prex表示),后缀和的最小值为未匹配的(的数量(sufn表示)。
如果未匹配的(,)都是偶数的话,那答案就是(prex+sufn)/2
如果未匹配的(,)都是奇数的话,那答案就是(prex+sufn)/2+1 (至于为什么,画一画括号找找规律啦)
翻转操作: 交换左右子树,打翻转标记,直接交换pre 和 suf 数组即可,因为以前的前缀变成了后缀,数值并未发生改变。
反转操作:打反转标记,将pren,prex,sufn,sufx,sum,key取反,swap(pren,prex),swap(sufn,sufx)。因为反转之后-1,与1,都会发生变化,而且取反后最大值与最小值都会发生大小交换。
有两个标记会不会发生标记冲突呢?这道题比较好,通过手动操作可以发现两个标记互不影响,先下放哪一个的效果都是相同的。
#include
#include
#include
#include
#include
#define N 500003
using namespace std;
int n,m,fa[N],size[N],sum[N],key[N],ch[N][3],prefx[N],prefn[N],sufx[N],sufn[N];
int pos[N],root,neg[N],rev[N],cnt;
char s[N];
void update(int now)//前缀和的最大值是多出的)的数量(最大值应该大于等于0),后缀和的最小值是多出的( 的数量(最小值应该小于等于0)
{
prefx[0]=sufx[0]=-1000000000;
prefn[0]=sufn[0]=1000000000; key[0]=0;
int l=ch[now][0]; int r=ch[now][1];
size[now]=size[l]+size[r]+1;
sum[now]=sum[l]+sum[r]+key[now];
int lenp=max(sum[l]+key[now],sum[l]+prefx[r]+key[now]);
prefx[now]=max(lenp,prefx[l]);
lenp=min(sum[l]+key[now],sum[l]+prefn[r]+key[now]);
prefn[now]=min(lenp,prefn[l]);
int lens=max(sum[r]+key[now],sum[r]+sufx[l]+key[now]);
sufx[now]=max(lens,sufx[r]);
lens=min(sum[r]+key[now],sum[r]+sufn[l]+key[now]);
sufn[now]=min(lens,sufn[r]);
}
void change(int now)
{
swap(prefx[now],sufx[now]);
swap(prefn[now],sufn[now]);
}
void change1(int now)
{
sum[now]=-sum[now]; key[now]=-key[now];
prefx[now]=-prefx[now]; sufx[now]=-sufx[now];
prefn[now]=-prefn[now]; sufn[now]=-sufn[now];
swap(prefx[now],prefn[now]);
swap(sufn[now],sufx[now]);
}
void pushdown(int x)
{
if (rev[x])
{
change(ch[x][0]); change(ch[x][1]);
swap(ch[x][0],ch[x][1]);
rev[ch[x][0]]^=1; rev[ch[x][1]]^=1;
rev[x]=0;
}
if (neg[x])
{
change1(ch[x][0]); change1(ch[x][1]);
neg[ch[x][0]]^=1; neg[ch[x][1]]^=1;
neg[x]=0;
}
}
int build(int l,int r,int f)
{
if (l>r) return 0;
int mid=(l+r)/2; int now=++cnt;
key[now]=pos[mid]; fa[now]=f;
ch[now][0]=build(l,mid-1,now);
ch[now][1]=build(mid+1,r,now);
update(now);
//cout<0) ans1=0;
else ans1=-ans1;
if (ans<0) ans=0;
if (ans%2||ans1%2) printf("%d\n",(ans+ans1)/2+1);
else printf("%d\n",(ans+ans1)/2);
}
if (opt==1)
{
neg[t]^=1;
change1(t); update(ch[root][1]); update(root);
}
if (opt==2)
{
rev[t]^=1;
change(t); update(ch[root][1]); update(root);
}
}
}