P12720 题解
T611148 [Algo Beat Contest 002 G] Game Time
出题人题解
1. 考虑博弈部分
不难想到,谁赢只取决于最后一个
2. O(n^2m) 暴力
对于每次修改,枚举所有区间重新计算答案即可。
3. O(nm) 暴力
首先可以计算
3.1. 0 的贡献
这是简单的,对于一个长度为
3.2. 1 的贡献
设第
而
所以第
3.3. O(nm) 暴力
直接暴力修改然后按照上述方式计算答案即可。
4. O((n+m)\log n) 正解
注意到答案是可以用区间维护的,且可以将若干子区间合并计算出区间的答案。
于是可以用线段树维护区间
具体合并方式见代码注释。
5. 代码
#include<bits/stdc++.h>
#define ll long long
#define re register
#define fi first
#define se second
using namespace std;
inline ll read(){
ll res=0ll,f=1;
char c;
for(;(c=getchar())<'0'||c>'9';c=='-'?f=-f:0);
while(c>='0' && c<='9') res=(res<<1) + (res<<3) + c-'0',c=getchar();
return res*f;
}
inline ll Max(re ll x,re ll y){return x>y?x:y;}
inline ll Min(re ll x,re ll y){return x<y?x:y;}
inline void cmax(re auto &x,re auto y){x=Max(x,y);}
inline void cmin(re auto &x,re auto y){x=Min(x,y);}
/*-----------------*/
const int N=2e5+20;
int n,m,a[N];
inline ll g(re ll len){return len*(len+1)/2;}
struct P{
int l,r,h0,t0,id;// 左、右端点,左 0 的个数,右 0 的个数,最后一个 1 的编号
int num1,num2;// 奇数位上 1 的数量,偶数位上 1 的数量
ll sum1,sum2,ans;// 奇数位上 1 的权值和,偶数位上 1 的权值和
bool f;// 是否全 0
/*
权值:1 后面的 0 的数量 +1
<1> 00000000 + 00000000 = 0000000000000000
<2> 00000000 + 00100010 = 00100010 - 00 + 0000000000 + (len = 8) / 2 * (sum1 = 4) + (len - len / 2) * (sum2 = 2)
<3> 00100010 + 00000000 = 00100010 - 0 + 000000000 + (((id = 7) - (l = 1)) / 2 + 1) * (len = 8)
<4> 00100010 + 00110010 = 00100010 + 00110010 - 0 - 00 + 000 + ... + ...
*/
P friend operator +(P x,P y){
P z={x.l,y.r,0,0,0,0,0,0,0,0,0};
if(x.f&&y.f) return P{x.l,y.r,0,0,0,0,0,0,0,g(y.r-x.l+1),1};
else if(x.f){
int len=x.r-x.l+1;
z.h0=len+y.h0,z.t0=y.t0,z.id=y.id,z.f=0;
(len&1)?(z.sum1=y.sum2,z.sum2=y.sum1,z.num1=y.num2,z.num2=y.num1):
(z.sum1=y.sum1,z.sum2=y.sum2,z.num1=y.num1,z.num2=y.num2);
z.ans+=y.ans-g(y.h0)+g(z.h0);// 0 的贡献
z.ans+=(ll)len/2*y.sum1+(ll)(len-len/2)*y.sum2;// 1 的贡献
return z;
}
else if(y.f){
int len=y.r-y.l+1;
z.h0=x.h0,z.t0=x.t0+len,z.id=x.id,z.f=0;
z.num1=x.num1,z.num2=x.num2;
int a=x.id-x.l+1;
(a&1)?(z.sum1=x.sum1+len,z.sum2=x.sum2):
(z.sum1=x.sum1,z.sum2=x.sum2+len);
z.ans+=x.ans-g(x.t0)+g(z.t0);// 0 的贡献
z.ans+=(ll)(a+1)/2*len;// 1 的贡献
return z;
}
else{
int lx=x.r-x.l+1;
z.h0=x.h0,z.t0=y.t0,z.id=y.id,z.f=0;
/* x */
z.num1=x.num1,z.num2=x.num2;
int a=x.id-x.l+1;
(a&1)?(z.sum1=x.sum1+y.h0,z.sum2=x.sum2):
(z.sum1=x.sum1,z.sum2=x.sum2+y.h0);
/* y */
(lx&1)?(z.sum1+=y.sum2,z.sum2+=y.sum1,z.num1+=y.num2,z.num2+=y.num1):
(z.sum1+=y.sum1,z.sum2+=y.sum2,z.num1+=y.num1,z.num2+=y.num2);
/* ans */
z.ans+=g(x.t0+y.h0)-g(x.t0)-g(y.h0);// 0 的贡献
z.ans+=x.ans+(ll)(a+1)/2*y.h0;// x 的贡献
z.ans+=y.ans+(ll)lx/2*y.sum1+(ll)(lx-lx/2)*y.sum2;// y 的贡献
return z;
}
}
};
inline void Swap(re P &x,re P &y){
P z=x;x=y;y=z;
}
struct TR{
P t1[N<<2],t2[N<<2];bool la[N<<2];
#define mid ((l+r)>>1)
inline void build(re int p,re int l,re int r){
if(l==r){
if(a[l]&1){
t1[p]=P{l,l,0,0,l,1,0,1,0,1,0};
t2[p]=P{l,l,0,0,0,0,0,0,0,1,1};
}
else{
t1[p]=P{l,l,0,0,0,0,0,0,0,1,1};
t2[p]=P{l,l,0,0,l,1,0,1,0,1,0};
}
return;
}
build(p<<1,l,mid),build(p<<1|1,mid+1,r);
t1[p]=t1[p<<1]+t1[p<<1|1];
t2[p]=t2[p<<1]+t2[p<<1|1];
return;
}
inline void push_down(re int p){
if(!la[p]) return;
la[p<<1]^=1,la[p<<1|1]^=1;
Swap(t1[p<<1],t2[p<<1]);
Swap(t1[p<<1|1],t2[p<<1|1]);
la[p]=0;
}
inline void update(re int p,re int l,re int r,re int L,re int R){
if(r<L||R<l) return;
if(L<=l&&r<=R) return Swap(t1[p],t2[p]),la[p]^=1,void();
push_down(p),update(p<<1,l,mid,L,R),update(p<<1|1,mid+1,r,L,R);
t1[p]=t1[p<<1]+t1[p<<1|1],t2[p]=t2[p<<1]+t2[p<<1|1];
}
inline ll query(){return t1[1].ans;}
}tr;
int main(){
n=read();m=read();
for(re int i=1;i<=n;i++) a[i]=read();
tr.build(1,1,n);
while(m--){
int l,r;
l=read();r=read();
tr.update(1,1,n,l,r);
printf("%lld\n",tr.query());
}
return 0;
}