传送门:点我
Description
HH有一串由各种漂亮的贝壳组成的项链。HH相信不同的贝壳会带来好运,所以每次散步 完后,他都会随意取出一
段贝壳,思考它们所表达的含义。HH不断地收集新的贝壳,因此他的项链变得越来越长。有一天,他突然提出了一
个问题:某一段贝壳中,包含了多少种不同的贝壳?这个问题很难回答。。。因为项链实在是太长了。于是,他只
好求助睿智的你,来解决这个问题。
Input
第一行:一个整数N,表示项链的长度。
第二行:N个整数,表示依次表示项链中贝壳的编号(编号为0到1000000之间的整数)。
第三行:一个整数M,表示HH询问的个数。
接下来M行:每行两个整数,L和R(1 ≤ L ≤ R ≤ N),表示询问的区间。
N ≤ 50000,M ≤ 200000。
Output
M行,每行一个整数,依次表示询问对应的答案。
Sample Input
6
1 2 3 4 3 5
3
1 2
3 5
2 6
Sample Output
2
2
4
莫队
#include<stdio.h>
#include<algorithm>
#include<iostream>
#include<math.h>
#include<cstring>
#define go(i,a,b) for(int i=a;i<=b;i++)
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
const int M=200003;
const int N=500003;
struct Mo {
int l,r,ID;
} q[M];
int n,m,col[N],unit,Be[N];
int cnt[1000000+10],tot;
int ans[M];
bool cmp(Mo a,Mo b) {
return Be[a.l]==Be[b.l]?a.r<b.r:a.l<b.l;
}
inline void revise(int x,int add){
if(add==-1){
cnt[col[x]]+=add;
if(!cnt[col[x]]){ //如果该数的个数已经变为了0,计数减少一个
tot--;
}
}
else{
if(!cnt[col[x]]){//如果该数尚未开始计数,计数增加一个
tot++;
}
cnt[col[x]]+=add;
}
}
int main() {
scanf("%d",&n);
unit=sqrt(n);//分块 ,每一块的大小是unit
go(i,1,n)scanf("%d",&col[i]),Be[i]=i/unit+1;
scanf("%d",&m);
go(i,1,m)scanf("%d%d",&q[i].l,&q[i].r),q[i].ID=i;//询问请求的id
sort(q+1,q+m+1,cmp);
int l=1,r=0;
go(i,1,m) {
while(l<q[i].l)revise(l,-1),l++;
while(l>q[i].l)revise(l-1,1),l--;
while(r<q[i].r)revise(r+1,1),r++;
while(r>q[i].r)revise(r,-1),r--;
ans[q[i].ID]=tot;
}
go(i,1,m)printf("%d\n",ans[i]);
return 0;
}
在落谷上面莫队算法最后两个点竟然被卡掉了,qwq,后来看 了别人的离线+树状数组的做法,但是wa了后面的三个点,自己也不知道为什么,来往的大佬望指教,
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int M=200003;
const int N=500003;
int c[N];
int a[N];
int vis[N],nex[N];
int n,m;
int ans[M];
struct query{
int l,r;
int ind;
}q[M];
int cmp(query a,query b){
return a.l<b.l;
}
int lowbit(int x){
return x&(-x);
}
void add(int x,int num){
while(x<=n){
c[x]+=num;
x+=lowbit(x);
}
}
int getsum(int x){
int s=0;
while(x>0){
s+=c[x];
x-=lowbit(x);
}
return s;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
scanf("%d",&m);
for(int i=1;i<=m;i++){
scanf("%d%d",&q[i].l,&q[i].r);
q[i].ind=i;
}
for(int i=1;i<=n;i++){
if(!vis[a[i]]){
vis[a[i]]=1;
add(i,1);
}
}
for(int i=1;i<=n;i++){
vis[a[i]]=0;
}
for(int i=n;i;--i){
if(!vis[a[i]]){
nex[i]=n+1;
}
else{
nex[i]=vis[a[i]];
}
vis[a[i]]=i;
}
sort(q+1,q+m+1,cmp);
int j=1;
for(int i=1;i<=m;++i){
for(;j<q[i].l;j++)add(nex[j],1);
ans[q[i].ind]=getsum(q[i].r)-getsum(q[i].l-1);
}
for(int i=1;i<=m;i++){
printf("%d\n",ans[i]);
}
return 0;
}
后来又用了主席树, 不怎么会,所以直接套了一个板子,但是只过了前面三个点,其余的都是RE,
呜呜呜,过往的大牛指点一二
#include<iostream>
#include<cstdio>
#include<map>
using namespace std;
const int maxn=500000+5;
const int m=maxn*40;
int n,q,tot;
int a[maxn];
int T[maxn],lson[m],rson[m],c[m];
int build(int l,int r){
int root=tot++;
c[root]=0;
if(l!=r){
int mid=(r+l)>>1;
lson[root]=build(1,mid);
rson[root]=build(mid+1,r);
}
return root;
}
int update(int root,int pos,int val){
int newroot=tot++,tmp=newroot;
c[newroot]=c[root]+val;
int l=1,r=n;
while(l<r){
int mid=(l+r)>>1;
if(pos<=mid){
lson[newroot]=tot++;rson[newroot]=rson[root];
newroot=lson[newroot];root=lson[root];
r=mid;
}
else{
rson[newroot]=tot++;lson[newroot]=lson[root];
newroot=rson[newroot];root=rson[root];
l=mid+1;
}
c[newroot]=c[root]+val;
}
return tmp;
}
int query(int root,int pos){
int ret=0;
int l=1,r=n;
while(pos<r){
int mid=(l+r)>>1;
if(pos<=mid){
r=mid;
root=lson[root];
}
else{
ret+=c[lson[root]];
root=rson[root];
l=mid+1;
}
}
return ret+c[root];
}
int main(){
while(scanf("%d",&n)==1){
tot=0;
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
T[n+1]=build(1,n);
map<int,int>mp;
for(int i=n;i>=1;i--){
if(mp.find(a[i])==mp.end()){
T[i]=update(T[i+1],i,1);
}
else{
int tmp=update(T[i+1],mp[a[i]],-1);
T[i]=update(tmp,i,1);
}
mp[a[i]]=i;
}
scanf("%d",&q);
while(q--){
int l,r;
scanf("%d%d",&l,&r);
printf("%d\n",query(T[l],r));
}
}
return 0;
}