2821: 作詩(Poetize)
Time Limit: 50 Sec Memory Limit: 128 MB
Submit: 3265 Solved: 951
[Submit][Status][Discuss]
Description
神犇SJY虐完HEOI之後給傻×LYD出了一題:SHY是T國的公主,平時的一大愛好是作詩。由於時間緊迫,SHY作完詩
之後還要虐OI,於是SHY找來一篇長度為N的文章,閱讀M次,每次只閱讀其中連續的一段[l,r],從這一段中選出一
些漢字構成詩。因為SHY喜歡對偶,所以SHY規定最後選出的每個漢字都必須在[l,r]裡出現了正偶數次。而且SHY認
為選出的漢字的種類數(兩個一樣的漢字稱為同一種)越多越好(為了拿到更多的素材!)。於是SHY請LYD安排選
法。LYD這種傻×當然不會了,於是向你請教……問題簡述:N個數,M組詢問,每次問[l,r]中有多少個數出現正偶
數次。
Input
輸入第一行三個整數n、c以及m。表示文章字數、漢字的種類數、要選擇M次。第二行有n個整數,每個數Ai在[1, c
]間,代表一個編碼為Ai的漢字。接下來m行每行兩個整數l和r,設上一個詢問的答案為ans(第一個詢問時ans=0),
令L=(l+ans)mod n+1, R=(r+ans)mod n+1,若L>R,交換L和R,則本次詢問為[L,R]。
Output
輸出共m行,每行一個整數,第i個數表示SHY第i次能選出的漢字的最多種類數。
Sample Input
5 3 5
1 2 2 3 1
0 4
1 2
2 2
2 3
3 5
1 2 2 3 1
0 4
1 2
2 2
2 3
3 5
Sample Output
2
0
0
0
1
0
0
0
1
HINT
對於100%的資料,1<=n,c,m<=10^5
題解
分塊,每塊大小為sqrt(n/logn)
維護兩個塊內的ans
對於查詢操作:
若並未經過完整的塊,暴力求解
若經過了完整的塊,二分不在塊內的至多(2*塊的大小)個元素的值在詢問區間內出現的次數和在詢問區間內的整塊中出現的次數
判斷對答案的影響
程式碼
//by 減維
#include<cstdio>
#include<iostream>
#include<cstring>
#include<queue>
#include<cstdlib>
#include<ctime>
#include<cmath>
#include<map>
#include<bitset>
#include<algorithm>
#define ll long long
#define maxn 100005
#define inf 1<<30
using namespace std; struct node{int v,p;}b[maxn]; int n,c,m,blo,a[maxn],pos[maxn],tmp[maxn],fir[maxn],las[maxn],mark[maxn];
int f[][],L[],R[]; bool cmp(const node&x,const node&y)
{
if(x.v==y.v)return x.p<y.p;
return x.v<y.v;
} void pre()
{
int tot;
for(int i=;i<=pos[n];++i)
{
for(int j=L[i];j<=n;++j)tmp[a[j]]=;
tot=;
for(int j=L[i];j<=n;++j)
{
if(tmp[a[j]]%==&&tmp[a[j]]!=)tot--;
tmp[a[j]]++;
if(tmp[a[j]]%==&&tmp[a[j]]!=)tot++;
f[i][pos[j]]=tot;
}
}
for(int i=;i<=n;++i)b[i].v=a[i],b[i].p=i;
sort(b+,b+n+,cmp);
for(int i=;i<=n;++i){
if(!fir[b[i].v])fir[b[i].v]=i;
las[b[i].v]=i;
}
} int findup(int x,int val)
{
int l=fir[val],r=las[val];
int tmp=;
while(l<=r)
{
int mid=(l+r)>>;
if(x<b[mid].p)r=mid-;
else l=mid+,tmp=mid;
}
return tmp;
} int finddown(int x,int val)
{
int l=fir[val],r=las[val];
int tmp=inf;
while(l<=r)
{
int mid=(l+r)>>;
if(x>b[mid].p)l=mid+;
else r=mid-,tmp=mid;
}
return tmp;
} int find(int l,int r,int val)
{
return max(findup(r,val)-finddown(l,val)+,);
} int query(int x,int y)
{
int ans=,a1,t1,t2;
if(pos[x]==pos[y]||pos[x]+==pos[y])
{
for(int i=x;i<=y;++i)mark[a[i]]++;
for(int i=x;i<=y;++i)
{
if(mark[a[i]]%==&&mark[a[i]]!=)ans++;
mark[a[i]]=;
}
return ans;
}
int l=L[pos[x]+],r=R[pos[y]-];
ans=f[pos[x]+][pos[y]-];
for(int i=x;i<=y;++i)
{
if(i==l)i=r+;
a1=a[i];if(mark[a1])continue;
t1=find(x,y,a1),t2=find(l,r,a1);
if(t1%==){
if(t2%!=||t2==)ans++;
}else if(t1%==){
if(t2%==&&t2!=)ans--;
}
mark[a1]=;
}
for(int i=x;i<l;++i)mark[a[i]]=;
for(int i=r+;i<=y;++i)mark[a[i]]=;
return ans;
} int main()
{
scanf("%d%d%d",&n,&c,&m);
blo=sqrt(n/log2(n));
for(int i=;i<=n;++i)scanf("%d",&a[i]),pos[i]=(i-)/blo+;
for(int i=;i<=pos[n];++i)L[i]=(i-)*blo+,R[i]=i*blo;
R[pos[n]]=n;
pre();
int ans=;
for(int i=,x,y;i<=m;++i)
{
scanf("%d%d",&x,&y);
x=(x+ans)%n+,y=(y+ans)%n+;
if(x>y)swap(x,y);
ans=query(x,y);
printf("%d\n",ans);
}
return ;
}