题解:P12720 [Algo Beat Contest 002 G] Game Time
P12720 [Algo Beat Contest 002 G] Game Time
游戏的部分很简单,因为怎样都可以一步把答案的奇偶性改变,所以游戏的结果只取决于最后一个 1 的位置。
现在我们要做的就是,算最后一个 1 在奇数位上/没有 1 的子段个数。
容斥一下,算最后一个 1 在偶数位上的子段个数,答案为
对于一个 1 在
我们要求的就是
注意我们会少算最后一个 1 到边界的答案,记位置为
考虑反转操作,使用 FHQ-Treap,只要将两棵树的
综上时间复杂度
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=4e5+7;
int n,m;
#define ls tree[now].l
#define rs tree[now].r
int root[2],cnt;
struct node{
int val,sum,mx,mi;
int l,r,siz,wei;
}tree[maxn];
void pushup(int now){
tree[now].siz=tree[ls].siz+tree[rs].siz+1;
tree[now].sum=-tree[now].val*(tree[now].val/2);
if(ls) tree[now].sum+=tree[ls].sum+(tree[ls].mx/2)*(tree[now].val);
if(rs) tree[now].sum+=tree[rs].sum+(tree[now].val/2)*(tree[rs].mi);
tree[now].mi=ls?tree[ls].mi:tree[now].val;
tree[now].mx=rs?tree[rs].mx:tree[now].val;
// 维护子树和、子树下标最小/大值
}
int create(int val){
tree[++cnt]={val,-val*(val/2),val,val,0,0,1,rand()};
return cnt;
}
void split(int now,int val,int &rt1,int &rt2){
if(!now){ rt1=rt2=0; return; }
if(tree[now].val<=val){
rt1=now;
split(rs,val,rs,rt2);
}else{
rt2=now;
split(ls,val,rt1,ls);
}
pushup(now);
}
int merge(int rt1,int rt2){
if(!rt1||!rt2) return rt1+rt2;
if(tree[rt1].wei>tree[rt2].wei){
tree[rt1].r=merge(tree[rt1].r,rt2);
pushup(rt1);
return rt1;
}else{
tree[rt2].l=merge(rt1,tree[rt2].l);
pushup(rt2);
return rt2;
}
}
void ins(int val,int wt){
int x,y;
split(root[wt],val-1,x,y);
root[wt]=merge(merge(x,create(val)),y);
}
void swp(int l,int r){ // 交换
int a,b,c,d,e,f,g,h;
split(root[0],l-1,a,g);
split(g,r,b,c);
split(root[1],l-1,d,h);
split(h,r,e,f);
root[0]=merge(merge(a,e),c);
root[1]=merge(merge(d,b),f);
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
cin>>n>>m;
for(int i=1,x;i<=n;i++)
cin>>x, ins(i,x);
for(int i=1,l,r;i<=m;i++){
cin>>l>>r; swp(l,r);
cout<<n*(n+1)/2-tree[root[1]].sum-(n+1)*(tree[root[1]].mx/2)<<'\n';
}
return 0;
}