日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

HDU - 5919 Sequence II——主席树+区间种类++逆序建树

發(fā)布時間:2023/11/30 编程问答 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 HDU - 5919 Sequence II——主席树+区间种类++逆序建树 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

【題目描述】
HDU - 5919 Sequence II

【題目分析】
題目給定一個數(shù)組,每次查詢一個區(qū)間,找出區(qū)間內(nèi)不同數(shù)字的個數(shù)x,然后輸出按出現(xiàn)順序第x/2向上取整個數(shù)字的位置。

  • 按照要求,我們首先需要能夠找出給定區(qū)間不同的數(shù)字個數(shù)。
    首先,我們分析一個簡單一些的問題:對于右端點固定的區(qū)間,如何計算不同左區(qū)間內(nèi)不同數(shù)字的個數(shù)。
    我們不妨用一個數(shù)組記錄cntcntcnt哪些位置出現(xiàn)了一個不同的數(shù)字,用sumsumsum數(shù)組進(jìn)行維護(hù)cnt[1..l]cnt[1..l]cnt[1..l]的和(可以用線段樹或者樹狀數(shù)組),那么對于區(qū)間[l,r][l,r][l,r]內(nèi)不同數(shù)字的個數(shù)就是sum[r]?sum[l?1]sum[r]-sum[l-1]sum[r]?sum[l?1]
    在從前往后進(jìn)行添加的過程中,如果該數(shù)字在前面已經(jīng)出現(xiàn),就將前面的標(biāo)記消除,在后面的位置進(jìn)行標(biāo)記,也就是說盡可能將標(biāo)記后放。例如對于數(shù)組1,2,2,3,5,11,2,2,3,5,11,2,2,3,5,1維護(hù)以后的cntcntcnt數(shù)組就是0,0,1,1,1,10,0,1,1,1,10,0,1,1,1,1,這樣做的原因是我們假設(shè)的是右端點固定,對于重復(fù)的元素,在后面如果出現(xiàn)過前面就沒有必要標(biāo)記。
    如果詢問是離線的,我們大可以先將詢問保存下來,然后從前往后加入數(shù)據(jù)的過程中不斷將對應(yīng)的詢問答案保存(對應(yīng)是指右端點相同),最后輸出就可以了。
    可是這個問題是強(qiáng)制在線的,所以我們必須使用主席樹進(jìn)行可持久化。可是這種可持久化和以前的主席樹運(yùn)用不同,因為在添加的過程中會將前面的標(biāo)記消除,所以不同根節(jié)點的主席樹不在擁有可以互相加減的能力(加減的結(jié)果不再有意義)。然而在我們這個問題里面我們是不需要進(jìn)行加減的。
  • 不同于求區(qū)間第K大的時候我們的主席樹維護(hù)的是值區(qū)間,即值在區(qū)間內(nèi)的個數(shù),這里根節(jié)點的1..n1..n1..n指的是數(shù)據(jù)范圍aiaiai的最大值。在這里我們的根節(jié)點的1..n1..n1..nnnn指的是數(shù)據(jù)的個數(shù),就是題目中的nnn,標(biāo)記的是該位置上出現(xiàn)了一個之前沒有出現(xiàn)過的數(shù)字。 因此對于每次詢問,我們訪問的版本里保存的就是實際的數(shù)組,直接計數(shù)就可以。而區(qū)間第K大就需要減去之前的版本才是該區(qū)間內(nèi)的數(shù)的個數(shù)。
  • 題目要求的是數(shù)據(jù)第一次出現(xiàn)的位置,可是按照上面的想法進(jìn)行建樹的話我們保存的是當(dāng)前區(qū)間[1,i][1,i][1,i]數(shù)據(jù)最后一次出現(xiàn)的位置。很自然,我們應(yīng)該進(jìn)行逆序建樹,這樣的話我們保存的就是[i,n][i,n][i,n]區(qū)間內(nèi)數(shù)據(jù)第一次出現(xiàn)的位置,對于需要查詢的區(qū)間[l,r][l,r][l,r],我們訪問第lll個版本的主席樹,就滿足題目要求啦。
    求出數(shù)字的個數(shù)后我們再除以2向上取整就是題目要求的k,然后在找出對應(yīng)的位置,這里類似區(qū)間第K大
    【參考文獻(xiàn)】
    大佬博客1
    大佬博客2
    【AC代碼】
#include<cstdio> #include<cstring> #include<algorithm> #include<queue> #include<vector> #include<set> #include<climits> #include<string> #include<cmath> #include<cstdlib>using namespace std;const int MAXN=200005; int a[MAXN]; int n,m; struct node {int ls,rs,cnt; }tree[MAXN*40]; int root[MAXN*40]; int b[MAXN]; int tot;void Insert(int &now,int pre,int x,int l,int r,int add) {int tmp=now; now=++tot;tree[now]=tmp?tree[tmp]:tree[pre];tree[now].cnt+=add;if(l==r) return;int mid=(l+r)>>1;if(x<=mid) Insert(tree[now].ls,tree[pre].ls,x,l,mid,add);else Insert(tree[now].rs,tree[pre].rs,x,mid+1,r,add); }int GetSum(int k,int l,int r,int L,int R) {if(l>=L && r<=R) return tree[k].cnt;int ret=0; int mid=(l+r)>>1;if(L<=mid) ret+=GetSum(tree[k].ls,l,mid,L,R);if(R>mid) ret+=GetSum(tree[k].rs,mid+1,r,L,R);return ret; }int query(int k,int l,int r,int x) {if(l==r) return l;int mid=(l+r)>>1;int tmp=tree[tree[k].ls].cnt;if(x<=tmp) query(tree[k].ls,l,mid,x);else query(tree[k].rs,mid+1,r,x-tmp); }int main() {int T,ans,l,r,tmp,sum;scanf("%d",&T);for(int Case=1;Case<=T;Case++){scanf("%d%d",&n,&m);memset(tree,0,sizeof(tree));memset(a,0,sizeof(a));memset(b,0,sizeof(b));memset(root,0,sizeof(root));tot=0;for(int i=1;i<=n;i++){scanf("%d",&a[i]);}for(int i=n;i>0;i--){if(b[a[i]]) Insert(root[i],root[i+1],b[a[i]],1,n,-1);Insert(root[i],root[i+1],i,1,n,1);b[a[i]]=i;}ans=0;printf("Case #%d:",Case);//測試 //printf("\n");for(int i=0;i<m;i++){scanf("%d%d",&l,&r);l=(l+ans)%n+1; r=(r+ans)%n+1;if(l>r) tmp=l,l=r,r=tmp;//printf("test: l=%d r=%d\n",l,r);sum=GetSum(root[l],1,n,l,r);//printf("test: sum=%d\n",sum);sum=(sum+1)/2;//printf("test: sum=%d\n",sum);ans=query(root[l],1,n,sum);printf(" %d",ans);}printf("\n");}return 0; }

總結(jié)

以上是生活随笔為你收集整理的HDU - 5919 Sequence II——主席树+区间种类++逆序建树的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。