您的位置:首页 > 产品设计 > UI/UE

SPOJ DQUERY (主席树求区间不同数个数)

2016-10-07 21:08 489 查看

题意:找n个数中无修改的区间不同数个数

 

题解:使用主席树在线做,我们不能使用权值线段树建主席树

我们需要这么想:从左向右添加一到主席树上,添加的是该数字处在的位置

但是如果该数字前面出现过,就在此版本的主席树上的前面出现的位置减一,接着才在此位置上添一

这样查找是按照右区间版本的主席树来找(lef,rig)的数字

因为要将此区间每个不同的数都处在最后出现的位置

 

/*在线求区间内不同的数的个数:从头到尾添加到线段树(不是权值线段树,是存值的线段树)中
如果此数之前出现过就先减去,接着再加,最后在区间(l,r)中找到root[r]这个历史版本*/
#include<map>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define dir(a,b) (a>>b)
const int Max=30010;
int root[Max],tot,val[Max];
struct node
{
int lef,rig,sum;
}msegtr[Max*40];
map<int,int> mp;
void Init()
{
tot=0;
msegtr[0].lef=msegtr[0].rig=msegtr[0].sum=0;
root[0]=0;
mp.clear();
return;
}
void Create(int sta,int enn,int &x,int y,int pos,int aad)
{
msegtr[++tot]=msegtr[y];
msegtr[tot].sum+=aad;
x=tot;
if(sta==enn)
return;
int mid=dir(sta+enn,1);
if(mid>=pos)
Create(sta,mid,msegtr[x].lef,msegtr[y].lef,pos,aad);
else
Create(mid+1,enn,msegtr[x].rig,msegtr[y].rig,pos,aad);
return;
}
int Query(int sta,int enn,int x,int y)//只有左边有界限
{
if(sta>=y)
return msegtr[x].sum;
int mid=dir(sta+enn,1);
if(mid>=y)
return Query(sta,mid,msegtr[x].lef,y)+msegtr[msegtr[x].rig].sum;
else
return Query(mid+1,enn,msegtr[x].rig,y);
}
int main()
{
int n,m,temp;
int lef,rig;
while(~scanf("%d",&n))
{
Init();
for(int i=1;i<=n;++i)
{
scanf("%d",&val[i]);
if(!mp.count(val[i]))//直接加
{
Create(1,n,root[i],root[i-1],i,1);//注意是在i这个位置加1,不是权值线段树的val[i]位置加1
}
else
{
Create(1,n,temp,root[i-1],mp[val[i]],-1);//先在原位置减去1
Create(1,n,root[i],temp,i,1);
}
mp[val[i]]=i;
}
scanf("%d",&m);
for(int i=0;i<m;++i)
{
scanf("%d %d",&lef,&rig);
printf("%d\n",Query(1,n,root[rig],lef));//在rig的历史版本上找(lef,rig)的值
}
}
return 0;
}

 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: