嗯,一元体验场,让人体验到绝望。听出题人说,这是一套没有签到题的区域赛难度题目。如果有签到题,就是三题铜牌,然后我光荣一道题。算上遥远天国的签到题。嗯光荣两道题打铁。不说感想了。因为比赛是私有的。所以在这里只能分享一下题意题解,和我AC的代码。
题意:给n个数字和q次查询,q次查询包括两个值。l和r,问1到l区间和r到n区间不同的数字个数的。n和q的范围都是1e5.
题解:暴力超时加超内存。嗯,但是稍微改改就是裸的莫队算法。把n个数翻倍,那么原来的l + n 就是r, 原来的r 就是新的l。套莫队的板子即可
看代码
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+5*2;
struct node{
int lef,rig,id;
}Q[maxn];
int n,s[maxn],pos[maxn],block;
int m;
int Ans[maxn];
int val[maxn];
inline bool cmp(const node & a,const node & b){
if(pos[a.lef] != pos[b.lef]) return pos[a.lef] < pos[b.lef];
return pos[a.rig] < pos[b.rig];
}
inline void solve(){
int lef = 0,rig = 0,ans = 0;
for(int i = 1; i <= m ; i ++){
while(lef < Q[i].lef){
if(--val[s[lef++]] == 0) ans --;
}
while(lef > Q[i].lef){
if(val[s[--lef]]++ == 0) ans ++;
}
while(rig < Q[i].rig) {
if(val[s[++rig]]++ == 0) ans ++;
}
while(rig > Q[i].rig)
if(--val[s[rig--]] == 0) ans --;
Ans[Q[i].id] = ans;
}
return ;
}
int main(){
while(~scanf("%d%d",&n,&m)){
memset(val,0,sizeof(val));
block = sqrt(n);
for(int i = 1; i <= n ; i ++){
scanf("%d",&s[i]);
s[i+n] = s[i];
}
for(int i = 1; i <= n ; i ++)
pos[i] = (i-1)/block + 1;
for(int i = 1 ; i <= m ; i ++){
int a,b;
scanf("%d%d",&a,&b);
Q[i].lef = b;
Q[i].rig = a + n;
Q[i].id = i;
}
sort(Q+1,Q+1+m,cmp);
solve();
for(int i = 1; i <= m ; i++){
printf("%d\n",Ans[i]);
}
}
return 0;
}