這是乙個經典問題
n個數的數列a[1…n]
q次操作 :
1 l r x 區間[l,r] 加 x
2 l r k 詢問區間[l,r] 第k大的數
0n<105
,256mb 4 seconds
這個問題陳老師在一篇**中給了3種方法
我選擇了實現比較簡單的 二分+分塊
#include
#include
#include
using namespace std;
const int maxn=1e5+5,num=2e3;
int a[maxn],sa[maxn],tag[num],n,m,num;
inline void build()
for(int i=0;i<=n;i++)
for(int i=0;isort(sa+i*num,sa+i*num+num);
}}inline void change(int l,int r,int t)
if(r/num==n/num) return ;
for(int i=l/num*num;i*num+num;i++)
sort(sa+l/num*num,sa+r/num*num+num);
return ;
}for(int i=l/num+1;ifor(int i=l;i*num+num;i++)
for(int i=l/num*num;i*num+num;i++)
sort(sa+l/num*num,sa+l/num*num+num);
for(int i=r/num*num;i<=r;i++)
if(r/num==n/num) return ;
for(int i=r/num*num;i*num+num;i++)
sort(sa+r/num*num,sa+r/num*num+num);
}inline int query(int l,int r,int qn)
}return cnt;
}for(int i=l;i*num+num;i++)
}for(int i=r/num*num;i<=r;i++)
}for(int i=l/num+1;i*num,sa+i*num+num,qn-tag[i])-(sa+i*num);
}return cnt;
}inline int getkth(int l,int r,int k)
return top;
}int main()
else}}
return
0;}第一次寫分塊,寫了個驗證程式,也附上吧
資料生成
暴力驗證#include
#include
#include
const int maxn=1e5+5;
const int t=10;
int a[maxn];
int main()
}return
0;}
#include
#include
using
namespace
std;
const
int maxn=1e5+5;
int a[maxn],b[maxn],n,m;
int main()
if(op==1)else}}
return
0;}
帶修改區間k大
看了好久,後來自己想了一下。大概就是說因為原來的寫法下要修改的代價太大了,所以套上乙個樹狀陣列使每顆主席樹存特定幾個位置上的權值。平均一下修改和詢問的代價。include include include define n 2200001 using namespace std int n,m,tot...
帶修改的區間第k小 樹狀陣列套主席樹
題目鏈結 對乙個序列進行兩種操作 對於不待修改的區間第k kk小,我們可以用主席樹完成。我們來看看只用主席樹如何完成帶修改的區間第k kk小。對於每次修改,我們都需要把當前位置及以後的主席樹都進行修改。因此每次修改的時間複雜度為o n log n o nlog n o nlog n 空間增加o n ...
帶修改的主席樹
對於單點修改的主席樹,我們可以採用樹套樹來寫,原因 不會整體二分求帶修改的區間第k小。所以學習了一波 待修改的主席樹。真的是難寫,或者說碼量有點大。不過和三維偏序cdq分治相比其實差不了多少,但是cdq終究比樹套樹快而且空間消耗小。兩者都很不錯!經典題,但是對於我這個根本不懂樹套樹的人來說是有點難度...