SPOJ D-query(区间不同的数的个数)

题目

离线:树状数组

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN=(int)3e4+10;
struct node{
	int l,r,idx;
}qu[200010];
bool cmp(const node &a,const node &b){
	return a.r<b.r;
}
vector<int>v;
int a[MAXN],pre[MAXN],mark[MAXN];
int ans[200010];
int p[MAXN];
int n;
void add(int x,int y){
	while(x<=n){
		p[x]+=y;
		x+=x&(-x);
	}
}
int getsum(int x){
	ll re=0;
	while(x){
		re+=p[x];
		x-=x&(-x);
	}
	return re;
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
		v.push_back(a[i]);
	}
	sort(v.begin(),v.end());
	for(int i=1;i<=n;i++){
		a[i]=lower_bound(v.begin(),v.end(),a[i])-v.begin()+1;
		pre[i]=mark[a[i]];
		mark[a[i]]=i;
	}
	int m;
	scanf("%d",&m);
	for(int i=1;i<=m;i++){
		scanf("%d%d",&qu[i].l,&qu[i].r);
		qu[i].idx=i;
	}
	sort(qu+1,qu+1+m,cmp);
	int tmp=0;
	for(int i=1;i<=m;i++){
		while(tmp<qu[i].r){
			tmp++;
			if(pre[tmp]==0){
				add(1,1);
				add(tmp+1,-1);
			}
			else {
				add(pre[tmp]+1,1);
				add(tmp+1,-1);
			}
		}
		ans[qu[i].idx]=getsum(qu[i].l);
	}
	for(int i=1;i<=m;i++)printf("%d\n",ans[i]);
	return 0;
}

在线:主席树

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
const int MAXN=30005;
int a[MAXN],n,m,vsz,pre[MAXN];
vector<int>v;
int root[MAXN],ls[MAXN*40],rs[MAXN*40],add[MAXN*40],tot;
void build(int l,int r,int &rt){
	rt=++tot;
	if(l==r)return;
	int mid=l+r>>1;
	build(l,mid,ls[rt]);
	build(mid+1,r,rs[rt]);
}
void insert(int l,int r,int x,int y,int &r1,int r2){
	r1=++tot;ls[r1]=ls[r2];rs[r1]=rs[r2];add[r1]=add[r2];
	if(l==x&&r==y){add[r1]++;return ;}
	int mid=l+r>>1;
	if(mid>=y)insert(l,mid,x,y,ls[r1],ls[r2]);
	else if(mid<x)insert(mid+1,r,x,y,rs[r1],rs[r2]);
	else insert(l,mid,x,mid,ls[r1],ls[r2]),insert(mid+1,r,mid+1,y,rs[r1],rs[r2]);
}
int query(int l,int r,int x,int rt){
	if(l==r)return add[rt];
	int mid=l+r>>1;
	if(x<=mid)return add[rt]+query(l,mid,x,ls[rt]);
	else return add[rt]+query(mid+1,r,x,rs[rt]);
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
		v.push_back(a[i]);	
	}
	sort(v.begin(),v.end());
	v.erase(unique(v.begin(),v.end()),v.end());
	vsz=v.size();
	build(1,n,root[0]);
	for(int i=1;i<=n;i++){
		a[i]=lower_bound(v.begin(),v.end(),a[i])-v.begin()+1;	
		insert(1,n,pre[a[i]]+1,i,root[i],root[i-1]);
		pre[a[i]]=i;
	}
	scanf("%d",&m);
	while(m--){
		int l,r;
		scanf("%d%d",&l,&r);
		printf("%d\n",query(1,n,l,root[r]));
	}
	return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值