1. 程式人生 > >SPOJ3267/DQUERY:D-query——題解

SPOJ3267/DQUERY:D-query——題解

targe mes 線段 同時 amp ext htm getc html

https://vjudge.net/problem/SPOJ-DQUERY

http://www.spoj.com/problems/DQUERY/en/

給定一列數,查詢給定區間內數的種類數。

這題可以分塊做:BZOJ2453:維護隊列

但是我們不想分塊而且垃圾SPOJ可能會卡時間同時又想練主席樹,所以選擇主席樹。

參考:https://www.cnblogs.com/zhuanzhuruyi/p/5936713.html

這種題的主席樹建法並不是權值線段樹,而是正常線段樹。

當我們建樹過程中碰到的重復的數的時候,顯然讓該重復的數接近r是最好的,所以我們把前面的數刪掉,放到後面。

查詢的時候就是查詢rt[0]~rt[r],並且查詢的範圍在l~r的數的個數即可。

PS:rt[0]相當於沒有,範圍的上限r也可以省略。

#include<stack>
#include<queue>
#include<cstdio>
#include<cstring>
#include<bitset>
#include<algorithm>
using namespace std;
const int N=1e6+5;
inline int read(){
    int x=0,w=1;char ch=0;
    while(ch<0||ch>9){if(ch==
-)w=-1;ch=getchar();} while(ch>=0&&ch<=9){x=(x<<1)+(x<<3)+ch-0;ch=getchar();} return x*w; } struct tree{ int l,r,sum; }tr[N*20]; int n,m,rt[N],pool,in[N]; inline void insert(int y,int &x,int l,int r,int p,int v){ tr[x=++pool]=tr[y]; tr[x].sum
+=v; if(l==r)return; int mid=(l+r)>>1; if(p<=mid)insert(tr[y].l,tr[x].l,l,mid,p,v); else insert(tr[y].r,tr[x].r,mid+1,r,p,v); } inline int query(int x,int l,int r,int p){ if(p<=l)return tr[x].sum; if(r<p)return 0; int mid=(l+r)>>1; return query(tr[x].l,l,mid,p)+query(tr[x].r,mid+1,r,p); } int main(){ n=read(); for(int i=1;i<=n;i++){ int a=read(),tmp; if(!in[a]){ insert(rt[i-1],rt[i],1,n,in[a]=i,1); }else{ insert(rt[i-1],tmp,1,n,in[a],-1); insert(tmp,rt[i],1,n,in[a]=i,1); } } m=read(); for(int i=1;i<=m;i++){ int l=read(),r=read(); printf("%d\n",query(rt[r],1,n,l)); } return 0; }

+++++++++++++++++++++++++++++++++++++++++++

+本文作者:luyouqi233。               +

+歡迎訪問我的博客:http://www.cnblogs.com/luyouqi233/+

+++++++++++++++++++++++++++++++++++++++++++

SPOJ3267/DQUERY:D-query——題解