HDU - 5919 Sequence II——主席樹+區間種類++逆序建樹

【題目描述】
HDU - 5919 Sequence II
在這里插入圖片描述
【題目分析】
題目給定一個數組,每次查詢一個區間,找出區間內不同數字的個數x,然后輸出按出現順序第x/2向上取整個數字的位置。

  • 按照要求,我們首先需要能夠找出給定區間不同的數字個數。
    首先,我們分析一個簡單一些的問題:對于右端點固定的區間,如何計算不同左區間內不同數字的個數。
    我們不妨用一個數組記錄cntcntcnt哪些位置出現了一個不同的數字,用sumsumsum數組進行維護cnt[1..l]cnt[1..l]cnt[1..l]的和(可以用線段樹或者樹狀數組),那么對于區間[l,r][l,r][l,r]內不同數字的個數就是sum[r]?sum[l?1]sum[r]-sum[l-1]sum[r]?sum[l?1]
    在從前往后進行添加的過程中,如果該數字在前面已經出現,就將前面的標記消除,在后面的位置進行標記,也就是說盡可能將標記后放。例如對于數組1,2,2,3,5,11,2,2,3,5,11,2,2,3,5,1維護以后的cntcntcnt數組就是0,0,1,1,1,10,0,1,1,1,10,0,1,1,1,1,這樣做的原因是我們假設的是右端點固定,對于重復的元素,在后面如果出現過前面就沒有必要標記。
    如果詢問是離線的,我們大可以先將詢問保存下來,然后從前往后加入數據的過程中不斷將對應的詢問答案保存(對應是指右端點相同),最后輸出就可以了。
    可是這個問題是強制在線的,所以我們必須使用主席樹進行可持久化。可是這種可持久化和以前的主席樹運用不同,因為在添加的過程中會將前面的標記消除,所以不同根節點的主席樹不在擁有可以互相加減的能力(加減的結果不再有意義)。然而在我們這個問題里面我們是不需要進行加減的。
  • 不同于求區間第K大的時候我們的主席樹維護的是值區間,即值在區間內的個數,這里根節點的1..n1..n1..n指的是數據范圍aiaiai的最大值。在這里我們的根節點的1..n1..n1..nnnn指的是數據的個數,就是題目中的nnn,標記的是該位置上出現了一個之前沒有出現過的數字。 因此對于每次詢問,我們訪問的版本里保存的就是實際的數組,直接計數就可以。而區間第K大就需要減去之前的版本才是該區間內的數的個數。
  • 題目要求的是數據第一次出現的位置,可是按照上面的想法進行建樹的話我們保存的是當前區間[1,i][1,i][1,i]數據最后一次出現的位置。很自然,我們應該進行逆序建樹,這樣的話我們保存的就是[i,n][i,n][i,n]區間內數據第一次出現的位置,對于需要查詢的區間[l,r][l,r][l,r],我們訪問第lll個版本的主席樹,就滿足題目要求啦。
    求出數字的個數后我們再除以2向上取整就是題目要求的k,然后在找出對應的位置,這里類似區間第K大
    【參考文獻】
    大佬博客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;
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/384128.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/384128.shtml
英文地址,請注明出處:http://en.pswp.cn/news/384128.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Socket網絡編程--小小網盤程序(4)

http://www.cnblogs.com/wunaozai/p/3892729.html 在這一小節中實現了文件的下載&#xff0c;具體的思路是根據用戶的uid和用戶提供的文件名filename聯合兩張表&#xff0c;取得md5唯一標識符&#xff0c;然后操作這個標識符對應的文件發送給客戶端。 實現下載的小小網盤程序 …

靜態順序表的實現

實現對順序表的初始化&#xff0c;頭插&#xff0c;頭刪&#xff0c;尾插&#xff0c;尾刪&#xff0c; 任意下標的刪除&#xff0c; 任意下標處的的元素刪除&#xff0c;任意下標處的元素插入&#xff0c;任意元素的下標返回&#xff0c;任意下標處的元素返回&#xff0c; 刪除…

樹鏈剖分入門+HYSBZ - 1036樹的統計Count

今天學習了樹鏈剖分&#xff0c;記錄一下。 【題目背景】 HYSBZ - 1036樹的統計Count 【題目分析】 題目要求求任意結點之間路徑的和以及路徑上最大的結點&#xff0c;還有可能修改。如果正常做可能會很復雜&#xff08;我也不知道正常應該怎么做&#xff0c;應該要用到LCA什么…

Socket網絡編程--小小網盤程序(5)

http://www.cnblogs.com/wunaozai/p/3893469.html 各位好呀&#xff01;這一小節應該就是這個小小網盤程序的最后一小節了&#xff0c;這一節將實現最后的三個功能&#xff0c;即列出用戶在服務器中的文件列表&#xff0c;還有刪除用戶在服務器中的文件&#xff0c;最后的可以共…

進程相關概念

1.進程相關概念 進程是代碼的一次動態執行&#xff0c;擔當分配系統資源的角色&#xff0c;進程信息是被放在一個一個數據結構中&#xff0c;是一個結構體task_struct 2.進程控制塊內容 //linux下的進程控制塊 struct task_struct {volatile long state;// 說明了該進程是否可以…

SPOJ - QTREE3Query on a tree again!——樹鏈剖分

【題目描述】 SPOJ - QTREE3Query on a tree again! 【題目分析】 題目要求是輸出從111到xxx的路徑上遇到的第一個黑色的點。我們可以用樹鏈剖分&#xff08;不了解的同學請出門左拐&#xff0c;詳見樹鏈剖分入門&#xff09; 我們用線段樹維護每個區間第一次遇到黑點的位置&a…

C++中的函數指針和函數對象總結

http://www.cnblogs.com/lvpengms/archive/2011/02/21/1960078.html 篇一、函數指針 函數指針&#xff1a;是指向函數的指針變量&#xff0c;在C編譯時&#xff0c;每一個函數都有一個入口地址&#xff0c;那么這個指向這個函數的函數指針便指向這個地址。 函數指針的用途是很…

開發工具

1.編輯器 &#xff08;1&#xff09;vim ????vim是從vi發展出來的一個文本編輯器。代碼補完、編譯錯誤跳轉等方便編程的功能特別豐富&#xff0c;在程序員中被廣泛使用。 &#xff08;2&#xff09;sed ????sed是一種流編輯器&#xff0c;它一次處理一行內容。處理時…

575 div3RGB Substring (hard version)——思維-

【題目描述】 The only difference between easy and hard versions is the size of the input. You are given a string s consisting of n characters, each character is ‘R’, ‘G’ or ‘B’. You are also given an integer k . Your task is to change the minimum …

c++ 智能指針用法詳解

http://www.cnblogs.com/TenosDoIt/p/3456704.html 本文介紹c里面的四個智能指針: auto_ptr, shared_ptr, weak_ptr, unique_ptr 其中后三個是c11支持&#xff0c;并且第一個已經被c11棄用。 為什么要使用智能指針&#xff1a;我們知道c的內存管理是讓很多人頭疼的事&#xff0…

CodeForces - 786BLegacy——線段樹建圖+最短路

【題目描述】 CodeForces - 786BLegacy 【題目分析】 題目大概意思就是有三種操作&#xff1a; 從某個點到另一個點從某個點到另一個區間從某個區間到另一個點 然后詢問從其中一個點到其他所有點的距離——這很顯然是一個求單源最短路徑的。我們簡單的想法顯然是建一個圖&a…

自主編寫shell

1.替換原理 用fork創建子進程后執行的是和父進程相同的程序&#xff08;但有可能執行不同的代碼分支&#xff09;&#xff0c;子進程往往要調用一種exec函數以執行例外一個程序。當進程調用一種exec函數時&#xff0c;該進程的用戶空間代碼和數據完全被新程序替換&#xff0c;從…

HYSBZ - 2243染色——樹鏈剖分+線段樹建樹技巧

【題目描述】 HYSBZ - 2243染色 【題目分析】 我一直沒有看清楚題&#xff0c;以為求的是路徑上出現顏色的種類&#xff0c;然后就寫了一個區間染色的線段樹進行維護&#xff0c;過樣例的時候才發現題讀錯了&#xff0c;人家要求的是路徑上出現的顏色段&#xff0c;所以顏色的…

右值引用與轉移語義

https://www.ibm.com/developerworks/cn/aix/library/1307_lisl_c11/ 新特性的目的 右值引用 (Rvalue Referene) 是 C 新標準 (C11, 11 代表 2011 年 ) 中引入的新特性 , 它實現了轉移語義 (Move Sementics) 和精確傳遞 (Perfect Forwarding)。它的主要目的有兩個方面&#xff…

打動態庫和靜態庫

一.動態庫和靜態庫的定義 1.靜態庫 ????程序在編譯鏈接時把庫的代碼鏈接到可執行文件中。程序運行時就不再需要靜態庫 2.動態庫 ????程序在運行的時候才去鏈接動態庫的代碼&#xff0c;多個程序 共享使用代碼 3.動態鏈接 ????在執行文件之前&#xff0c;外部…

HYSBZ - 2157樹鏈剖分

【題目描述】 HYSBZ - 2157樹鏈剖分 【題目分析】 這道題給出的是邊權而不是點權&#xff0c;但是我們分析這個樹就會發現每個節點都只有一個父親&#xff0c;也就是每條邊的邊權都可以存放在兒子節點上&#xff0c;然后在遍歷路徑的時候我們在從前往后遍歷&#xff0c;但是注…

C++11中的右值引用

http://www.cnblogs.com/yanqi0124/p/4723698.html 在C98中有左值和右值的概念&#xff0c;不過這兩個概念對于很多程序員并不關心&#xff0c;因為不知道這兩個概念照樣可以寫出好程序。在C11中對右值的概念進行了增強&#xff0c;我個人理解這部分內容是C11引入的特性中最難以…

BZOJ2115XOR——線性基

【題目描述】 BZOJ2115XOR——線性基 【題目分析】 這道題看完以后很懵逼&#xff0c;人家要是走的很復雜呢&#xff1f;各種繞來繞去怎么辦&#xff1f; 首先我們應該注意到一個很明顯的道理&#xff1a;重復的路徑會和自身抵消&#xff0c;所以我們大可以隨便跑&#xff0c;…

單鏈表的相關操作

1.冒泡排序對單鏈表進行排序 void LinkListBubbleSort(LinkNode* head) {if(head NULL){ return;//空鏈表} if(head -> next NULL){ return;//只有一個結點} LinkNode* cur head;//趟數LinkNode* tail NULL;//尾指針LinkNode* tmp head;//次數for(; cur -…

socket網絡編程--epoll小結

http://www.cnblogs.com/wunaozai/p/3895860.html 以前使用的用于I/O多路復用為了方便就使用select函數&#xff0c;但select這個函數是有缺陷的。因為它所支持的并發連接數是有限的(一般小于1024)&#xff0c;因為用戶處理的數組是使用硬編碼的。這個最大值為FD_SETSIZE&#…