整體二分--poj2104靜態區間第k小
昨天跟yousiki學到了整體二分!quq
最經典的就是靜態區間第k小(大)
聽說2013許昊然的論文-《淺談資料結構題的幾個非經典解法》 講的特別好,從網上找了個圖
複雜度很優秀的說!
具體做法一般是:
1、找到詢問答案的上限和下限limit,開始二分
2、每次二分出一個mid,判斷答案在l~mid之間的詢問,如果有修改就判斷修改的影響是否在l~mid之間,然後將l到r內的操作分成兩部分,左邊是l~mid之間的,右邊是mid+1~r之間的
3、分別遞迴求解兩部分的答案
4、如果二分的val值vl==vr,l~r內詢問的答案已經確定,為vl,return
5、判斷部分一般需要資料結構支援
這道題的做法也差不多啦,資料結構支援單點加和區間求和,用樹狀陣列就可以
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> #define M 50005 #define N 100005 using namespace std; int n,m,f[N],mx,ans[M]; inline int rd(){ int x=0,f=1;char c=' '; while(c<'0' || c>'9') {if(c=='-')f=-1;c=getchar();} while(c<='9' && c>='0') x=x*10+c-'0',c=getchar(); return x*f; } struct qwq{ int val,num; }a[N]; inline bool cmp(qwq x,qwq y){return x.val<y.val;} struct Query{ int cnt,k,num,l,r; }q[M],b[M]; inline void add(int x,int y){ for(;x<=n;x+=x&-x) f[x]+=y; } inline int query(int x){ int sum=0; for(;x;x-=x&-x) sum+=f[x]; return sum; } inline void calc(int vl,int vr,int l,int r){ int ll=1,rr=n+1; while(ll<rr){//找到a陣列中大於等於vl的最後一個 int mid=(ll+rr)>>1; if(a[mid].val>=vl) rr=mid; else ll=mid+1; } for(int i=rr;i<=n && a[i].val<=vr;i++) add(a[i].num,1);//將小於等於mid的加入 for(int i=l;i<=r;i++) q[i].cnt=query(q[i].r)-query(q[i].l-1);//計算詢問在l~mid的答案 for(int i=rr;i<=n && a[i].val<=vr;i++)//記得還原 add(a[i].num,-1); } inline void solve(int l,int r,int vl,int vr){ if(vl==vr){ for(int i=l;i<=r;i++) ans[q[i].num]=vl; return; } int mid=(vl+vr)>>1; calc(vl,mid,l,r);//計算詢問中 int now1=l,now2=r; for(int i=l;i<=r;i++)//將詢問分成兩部分 if(q[i].cnt>=q[i].k) b[now1++]=q[i]; else q[i].k-=q[i].cnt,b[now2--]=q[i]; for(int i=l;i<=r;i++) q[i]=b[i];//合併兩部分 if(now1!=l) solve(l,now1-1,vl,mid);//遞迴求解 if(now2!=r) solve(now2+1,r,mid+1,vr); return; } int main(){ n=rd(); m=rd(); for(int i=1;i<=n;i++) a[i].val=rd(),a[i].num=i; a[n+1].val=1e9+5; sort(a+1,a+n+1,cmp); for(int i=1;i<=m;i++){ q[i].num=i; q[i].l=rd(); q[i].r=rd(); q[i].k=rd(); } solve(1,m,-1e9,1e9); for(int i=1;i<=m;i++) printf("%d\n",ans[i]); return 0; }
相關推薦
整體二分--poj2104靜態區間第k小
傳送門 昨天跟yousiki學到了整體二分!quq 最經典的就是靜態區間第k小(大) 聽說2013許昊然的論文-《淺談資料結構題的幾個非經典解法》 講的特別好,從網上找了個圖 複雜度很優秀的說! 具體做法一般是: 1、找到詢問答案的上限和下限limit,開始二
整體二分初步——靜態區間第k大
Description 給定一個長度為n的序列,m個詢問,每個詢問的形式為:L,r,k表示在[L,r]間中的第k大元素。 Input 第1行:2個數,n,m表示序列的長度和詢問的個數 第2行:n個數,表示n個數的大小 第3-m+2行:每行3個數,L,r,k表示詢問在[L
靜態區間第K小(整體二分、主席樹)
題目連結 題解 主席樹入門題 但是這裡給出整體二分解法 整體二分顧名思義是把所有操作放在一起二分 想想,如果求\([1-n]\)的第\(k\)小怎麼二分求得? 我們可以二分答案\(k\), \(O(n)\)統計有多少個數小於等於\(k\) 如果對於每個詢問都這麼搞,肯定不行 我們可以發現,如果
poj2104求區間第k小,靜態主席樹入門模板
看了很久的主席樹,最後看https://blog.csdn.net/williamsun0122/article/details/77871278這篇終於看懂了 #include <stdio.h> #include<algorithm> using namespace s
整體二分——帶修改區間第k大
Description 給定一個長度為N的已知序列A[i](1<=i<=N),要求維護這個序列,能夠支援以下兩種操作: 1、查詢A[i],A[i+1],A[i+2],…,A[j](1<=i<=j<=N)中,升序排列後排名第k的數。
整體二分求動態區間第k大
long long unsigned char else 樹狀數組 linker truct ati pos 比樹狀數組套主席樹不知道高到哪裏去了,solve(l,r,L,R)就是對於L,R的操作區間的答案都在l,r區間裏,然後遞歸下去 復雜度O(nlognlogn),每個
【XSY2720】區間第k小 整體二分 可持久化線段樹
cpp markdown 區間 序列 printf line 線段 using back 題目描述 給你你個序列,每次求區間第\(k\)小的數。 本題中,如果一個數在詢問區間中出現了超過\(w\)次,那麽就把這個數視為\(n\)。 強制在線。 \(n\leq
整體二分(模板) 求區間第k小
整體二分,將詢問與初值一起放入一個結構體裡,然後每次二分判斷詢問在哪邊,樹狀陣列維護,時間複雜度O((n+Q)lognlogMAX_a[i] 程式碼 #include<iostream
[poj 2104]主席樹+靜態區間第k大
include end 區間 得到 name int 題目 tar tdi 題目鏈接:http://poj.org/problem?id=2104 主席樹入門題目,主席樹其實就是可持久化權值線段樹,rt[i]維護了前i個數中第i大(小)的數出現次數的信息,通過查詢兩棵樹的差
poj 2104主席樹求區間第k小
區間 ++ cto ast http lan air algorithm while POJ - 2104 題意:求區間第k小 思路:無修改主席樹 AC代碼: #include "iostream" #include "iomanip" #include "string.
少年,想學帶修改主席樹嗎 | BZOJ1901 帶修改區間第k小
== write algo i++ sin esp 天下 read 一個 少年,想學帶修改主席樹嗎 | BZOJ1901 帶修改區間第k小 有一道題(BZOJ 1901)是這樣的:n個數,m個詢問,詢問有兩種:修改某個數/詢問區間第k小。 不帶修改的區間第k小用主席樹很好
靜態區間第k大 樹套樹解法
i++ val pri math 1+n std -a 平衡樹 scanf 然而過不去你谷的模板 思路: 值域線段樹\([l,r]\)代表一棵值域在\([l,r]\)範圍內的點構成的一顆平衡樹 平衡樹的\(BST\)權值為點在序列中的位置 查詢區間第\(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/Oth
HDU 5919 - Sequence II (2016CCPC長春) 主席樹 (區間第K小+區間不同值個數)
HDU 5919 題意: 動態處理一個序列的區間問題,對於一個給定序列,每次輸入區間的左端點和右端點,輸出這個區間中:每個數字第一次出現的位子留下, 輸出這些位子中最中間的那個,就是(len+1)/2那個。 思路: 主席樹操作,這裡的思路是從n到1開始建樹。其他就是主席樹查詢區間第K小,計算區
落谷 P3834 可持久化線段樹 1(主席樹)(區間第k小)
設區間為l,r,用r版本減去l版本求出區間第k小,一個板子 #include<cstdio> #include<cmath> #include<cstring> #include<algorithm> using
求區間第k小(主席樹)
區間第k小 題目描述 如題,給定NNN個正整數構成的序列,將對於指定的閉區間查詢其區間內的第KKK小值。 輸入格式 第一行包含兩個正整數NNN、MMM,分別表示序列的長度和查詢的個數。 第二行包含NN
可持久化線段樹——Step 1 靜態區間第K大
考慮這樣一個問題: 給出一段長度為n序列{ai},對於一些詢問{L,R,K}請輸出序列上[L,R]內第K大的數。 關於暴力做法,其實是很簡單的,但是會超時,在此略過。 有一種辦法,是利用字首和的思想。先將{ai}離散到區間[1,n],然後,對於任意節點i,
主席樹入門詳解一(學習筆記)(例題POJ-2104 求區間第k小)
學習主席樹,在網上搜了很多教程(都好簡短啊,直接就是幾行字就上程式碼,看不懂啊有木有~~),最後才很艱難的學會了最基礎的部分。下面就是我在學習的過程中的產生的疑惑和解決的辦法。 學習主席樹需要的前置技能:線段樹。 參考資料 1. B站上的視訊講解(話說B站真的啥都有啊)
靜態區間第K大
<a target=_blank href="http://poj.org/problem?id=2104" target="_blank"><span style="font-s
動態區間第k小(主席樹+線段樹套樹狀陣列)
靜態區間第k小問題,是給你一個序列,每次詢問序列中的一個區間中的第k小數,這個問題用普通的主席樹就可以解決。動態區間第k小問題就是在靜態的基礎上加上了修改操作,也就是每次除了詢問區間第k小之外,還可以修改序列中的某個數。因為這裡涉及到了修改操作,我們用只用主席樹