1. 程式人生 > >HDU 2665.Kth number-無修改區間第K小-可持久化線段樹(主席樹)模板

HDU 2665.Kth number-無修改區間第K小-可持久化線段樹(主席樹)模板

sort ota nbsp ani show 去重 第k小 math urn

Kth number

Time Limit: 15000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 16941 Accepted Submission(s): 5190


Problem Description Give you a sequence and ask you the kth big number of a inteval.

Input The first line is the number of the test cases.
For each test case, the first line contain two integer n and m (n, m <= 100000), indicates the number of integers in the sequence and the number of the quaere.
The second line contains n integers, describe the sequence.
Each of following m lines contains three integers s, t, k.
[s, t] indicates the interval and k indicates the kth big number in interval [s, t]

Output For each test case, output m lines. Each line contains the kth big number.

Sample Input 1 10 1 1 4 2 3 5 6 7 8 9 0 1 3 2

Sample Output 2

Source HDU男生專場公開賽——趕在女生之前先過節(From WHU) 題意就是查詢區間第K小,可持久化線段樹就可以上場了。 沒學可持久化數據結構之前,感覺這個東西是個很高大上,很厲害的東西,等到了解之後發現,就是因為問題的產生所以在原有線段樹的基礎上有所更新,支持查詢歷史版本。 如果每更新一次就新建一整棵線段樹簡直是喪心病狂,所以直接新開節點保存更新的那一條鏈就可以。 這種東西還是需要自己慢慢體會的,加油,鹹魚。 代碼:
  1 //無修改區間第K小-可持久化線段樹(權值線段樹+可持久化)
2 #include<iostream> 3 #include<cstdio> 4 #include<cstring> 5 #include<algorithm> 6 #include<bitset> 7 #include<cassert> 8 #include<cctype> 9 #include<cmath> 10 #include<cstdlib> 11 #include<ctime> 12 #include<deque> 13 #include<iomanip> 14 #include<list> 15 #include<map> 16 #include<queue> 17 #include<set> 18 #include<stack> 19 #include<vector> 20 using namespace std; 21 typedef long long ll; 22 typedef pair<int,int> pii; 23 24 const double PI=acos(-1.0); 25 const double eps=1e-6; 26 const ll mod=1e9+7; 27 const int inf=0x3f3f3f3f; 28 const int maxn=1e5+10; 29 const int maxm=100+10; 30 #define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); 31 #define lson l,m 32 #define rson m+1,r 33 34 int a[maxn],b[maxn],sum[maxn<<5],L[maxn<<5],R[maxn<<5];//sum線段樹裏保存的值,L左兒子,R右兒子 35 int n,m,sz=0; 36 37 void build(int &rt,int l,int r)//建棵空樹 38 { 39 rt=++sz;sum[rt]=0;//動態開點,初始值為0,空樹 40 if(l==r){ 41 return ; 42 } 43 44 int m=(l+r)>>1; 45 build(L[rt],lson); 46 build(R[rt],rson); 47 } 48 49 void update(int pr,int &rt,int l,int r,int x) 50 { 51 rt=++sz;sum[rt]=sum[pr]+1;//插入序列,首先繼承以前的線段樹 然後直接單點+1就可以 52 L[rt]=L[pr];R[rt]=R[pr]; 53 if(l==r){ 54 return ; 55 } 56 57 int m=(l+r)>>1; 58 if(x<=m) update(L[pr],L[rt],lson,x);//因為右邊不需要更新,所以覆蓋掉左邊 59 else update(R[pr],R[rt],rson,x); 60 } 61 62 int query(int pr,int rt,int l,int r,int x)//查詢l到r區間就是第r次插入減去第l-1次插入後的線段樹的樣子 63 { 64 if(l==r){ 65 return l; 66 } 67 //因為我們建立的是權值線段樹,所以直接查找就可以 68 int m=(l+r)>>1; 69 int now=sum[L[rt]]-sum[L[pr]];//now為左子樹新樹-舊樹 70 if(now>=x) return query(L[pr],L[rt],lson,x); 71 else return query(R[pr],R[rt],rson,x-now); 72 } 73 74 int rt[maxn]; 75 76 int main() 77 { 78 int t; 79 scanf("%d",&t); 80 while(t--){ 81 scanf("%d%d",&n,&m); 82 sz=0; 83 for(int i=1;i<=n;i++){ 84 scanf("%d",&a[i]); 85 b[i]=a[i]; 86 } 87 sort(b+1,b+1+n);//首先把值全部排序去重,用於建權值線段樹,權值線段樹保存的內容是值的數量。 88 int d=unique(b+1,b+1+n)-(b+1); 89 build(rt[0],1,d); 90 for(int i=1;i<=n;i++){//按照序列順序插入值 91 int x=lower_bound(b+1,b+1+d,a[i])-b; 92 update(rt[i-1],rt[i],1,d,x); 93 } 94 for(int i=1;i<=m;i++){ 95 int l,r,k; 96 scanf("%d%d%d",&l,&r,&k); 97 printf("%d\n",b[query(rt[l-1],rt[r],1,d,k)]); 98 } 99 } 100 return 0; 101 }

你來到人間,就是要看看太陽,看看外面有趣的世界。

HDU 2665.Kth number-無修改區間第K小-可持久化線段樹(主席樹)模板