P3870-[TJOI2009]开关【分块】
生活随笔
收集整理的這篇文章主要介紹了
P3870-[TJOI2009]开关【分块】
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
正題
解題思路:https://www.luogu.org/recordnew/lists?uid=52918&pid=P3870
題目大意
n個燈,操作[0,l,r][0,l,r][0,l,r]表示l~rl\sim rl~r的燈取反,操作[1,l,r][1,l,r][1,l,r]表示詢問l~rl\sim rl~r之間有多少燈亮著。
解題思路
分塊,對于每個塊維護兩個值sum,fsum,fsum,f。sum表示這個塊有多少個開著的燈,f表示這個塊是否取反。
由于有了f所以我們對于塊就可以不用取反了。
code
#include<cstdio> #include<cmath> #define pos(x) (x-1)/sq+1 #define N 100010 #define T 500 using namespace std; int n,m,l,r,x,sq,t; bool a[N],f[T]; int L[T],R[T],sum[T]; void ycl() {sq=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; } void change(int l,int r) {int q=pos(l),p=pos(r);if(q==p){for(int i=l;i<=r;i++)sum[p]+=1-a[i]*2,a[i]=!a[i];}else{for(int i=q+1;i<=p-1;i++)f[i]=!f[i];for(int i=l;i<=R[q];i++)sum[q]+=1-a[i]*2,a[i]=!a[i];for(int i=L[p];i<=r;i++)sum[p]+=1-a[i]*2,a[i]=!a[i];} } int ask(int l,int r) {int ans=0;int q=pos(l),p=pos(r);if(q==p){for(int i=l;i<=r;i++)ans+=a[i];if(f[p]) return r-l+1-ans;return ans;}else{for(int i=q+1;i<=p-1;i++)if(f[i]) ans+=R[i]-L[i]+1-sum[i];else ans+=sum[i];int k=0;for(int i=l;i<=R[q];i++)k+=a[i];if(f[q]) ans+=R[q]-l+1-k;else ans+=k;k=0;for(int i=L[p];i<=r;i++)k+=a[i];if(f[p]) ans+=r-L[p]+1-k;else ans+=k;}return ans; } int main() {scanf("%d%d",&n,&m);ycl();for(int i=1;i<=m;i++){scanf("%d%d%d",&x,&l,&r);if(x) printf("%d\n",ask(l,r));else change(l,r);} }總結
以上是生活随笔為你收集整理的P3870-[TJOI2009]开关【分块】的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: b站怎么循环播放一个视频
- 下一篇: 恩格尔系数在多少为小康水平 恩格尔系数多