1. 程式人生 > >2018.09.30 bzoj2821: 作詩(Poetize)(分塊)

2018.09.30 bzoj2821: 作詩(Poetize)(分塊)

傳送門 分塊經典題目。

先將數列分塊。 然後預處理出每兩個塊之間有多少個數出現了正偶數次。 這樣查詢的時候對於中間的完整塊直接用預處理出的陣列搞定。 剩下的暴力列舉求解。 程式碼:

#include<bits/stdc++.h>
#define N 100005
using namespace std;
inline int read(){
    int ans=0;
    char ch=getchar();
    while(!isdigit(ch))ch=getchar();
    while(isdigit(ch))ans=(ans<<3)+(ans<<
1)+(ch^48),ch=getchar(); return ans; } int n,c,m,a[N],lastans,blo[N],cnt[N],cal[255][N],sum[255][255],sig=500,blos; inline int query(int ql,int qr){ int l=blo[ql],r=blo[qr],ret=0; if(r-l<2){ for(int i=ql;i<=qr;++i){ ++cnt[a[i]]; if(!(cnt[a[i]]&1))++
ret; else if(cnt[a[i]]>2)--ret; } for(int i=ql;i<=qr;++i)--cnt[a[i]]; return ret; } ret+=sum[l+1][r-1]; for(int i=ql;i<=l*sig;++i){ ++cnt[a[i]]; int tmp=cnt[a[i]]+cal[r-1][a[i]]-cal[l][a[i]]; if(!(tmp&1))++ret; else
if(tmp>2)--ret; } for(int i=(r-1)*sig+1;i<=qr;++i){ ++cnt[a[i]]; int tmp=cnt[a[i]]+cal[r-1][a[i]]-cal[l][a[i]]; if(!(tmp&1))++ret; else if(tmp>2)--ret; } for(int i=ql;i<=l*sig;++i)--cnt[a[i]]; for(int i=(r-1)*sig+1;i<=qr;++i)--cnt[a[i]]; return ret; } int main(){ n=read(),c=read(),m=read(); for(int i=1;i<=n;++i)++cal[(blo[i]=(i-1)/sig+1)][(a[i]=read())]; blos=blo[n]; for(int i=1;i<=c;++i)for(int j=1;j<=blos;++j)cal[j][i]+=cal[j-1][i]; for(int i=1;i<=blos;++i){ int tmp=0; for(int j=(i-1)*sig+1;j<=n;++j){ ++cnt[a[j]]; if(!(cnt[a[j]]&1))++tmp; else if(cnt[a[j]]>2)--tmp; sum[i][blo[j]]=tmp; } for(int j=(i-1)*sig+1;j<=n;++j)--cnt[a[j]]; } while(m--){ int l=(read()+lastans)%n+1,r=(read()+lastans)%n+1; if(l>r)swap(l,r); printf("%d\n",lastans=query(l,r)); } return 0; }