专栏文章
题解:P12720 [Algo Beat Contest 002 G] Game Time
P12720题解参与者 4已保存评论 4
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 4 条
- 当前快照
- 1 份
- 快照标识符
- @mip4dhi9
- 此快照首次捕获于
- 2025/12/03 05:58 3 个月前
- 此快照最后确认于
- 2025/12/03 05:58 3 个月前
P12720 [Algo Beat Contest 002 G] Game Time
游戏的部分很简单,因为怎样都可以一步把答案的奇偶性改变,所以游戏的结果只取决于最后一个 1 的位置。
现在我们要做的就是,算最后一个 1 在奇数位上/没有 1 的子段个数。
容斥一下,算最后一个 1 在偶数位上的子段个数,答案为 减去这个。
对于一个 1 在 ,下一个 1 /边界在 ,它作为最后一个 1 的区间为 ,而且只有 对答案有影响,即要求 和 一奇一偶,所以这个 1 的贡献为 。
我们要求的就是 ,说明答案只与相邻位的下标有关。考虑对于所有值为 0/1 的下标建平衡树,节点维护下标 、子树答案和 、子树下标最小/大值 ,我们 pushup 的过程相当于把三段相邻的合并。也就是左子树最大下标和当前根、根和右子树最小下标合并,即
注意我们会少算最后一个 1 到边界的答案,记位置为 ,此时把答案加上 即可。
考虑反转操作,使用 FHQ-Treap,只要将两棵树的 范围的树分裂下来然后交换拼回去即可。
综上时间复杂度 。好写。
CPP#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;
}
相关推荐
评论
共 4 条评论,欢迎与作者交流。
正在加载评论...