P3870 [TJOI2009]开关 题解
作者:互联网
Link
Solve
把序列分成\(\sqrt{N}\)个块,每个块整体处理时亮着的灯数=块内灯总数-前一时刻亮着的灯数,块外的单独处理就好了。
貌似线段树也是这种统计方式
Code
#include<bits/stdc++.h>
using namespace std;
const int maxn=100005;
int N,Q,a[maxn],L[maxn],pos[maxn],R[maxn],add[maxn],sum[maxn],t,light[maxn];
inline int read(){
int ret=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-f;ch=getchar();}
while(ch<='9'&&ch>='0')ret=ret*10+ch-'0',ch=getchar();
return ret*f;
}
void change(int l,int r){
int p=pos[l],q=pos[r];
if(p==q){
for(int i=l;i<=r;i++){
a[i]^=1;
if(a[i]^add[p])light[p]++;
else light[p]--;
}
}
else {
for(int i=p+1;i<=q-1;i++){add[i]^=1;light[i]=sum[i]-light[i];}
for(int i=l;i<=R[p];i++){
a[i]^=1;
if(a[i]^add[p])light[p]++;
else light[p]--;
}
for(int i=L[q];i<=r;i++){
a[i]^=1;
if(a[i]^add[q])light[q]++;
else light[q]--;
}
}
return ;
}
int query(int l,int r){
int ans=0,p=pos[l],q=pos[r];
if(p==q){
for(int i=l;i<=r;i++)ans+=a[i]^add[p];
}
else{
for(int i=p+1;i<=q-1;i++)ans+=light[i];
for(int i=l;i<=R[p];i++)ans+=a[i]^add[p];
for(int i=L[q];i<=r;i++)ans+=a[i]^add[q];
}
return ans;
}
int main(){
freopen("P3870.in","r",stdin);
freopen("P3870.out","w",stdout);
N=read();Q=read();
t=sqrt(N);
for(int i=1;i<=t;i++){
L[i]=(i-1)*t+1;
R[i]=i*t;
}
if(R[t]<N){t++;L[t]=R[t-1]+1;R[t]=N;}
for(int i=1;i<=t;i++)
for(int j=L[i];j<=R[i];j++){
pos[j]=i;
sum[i]++;
}
while(Q--){
int op=read(),l=read(),r=read();
if(!op)change(l,r);
else printf("%d\n",query(l,r));
}
return 0;
}
标签:ch,int,题解,pos,ret,maxn,P3870,TJOI2009,getchar 来源: https://www.cnblogs.com/martian148/p/13883283.html