【TJOI2016】【bzoj4552】排序(二分答案+線段樹01排序)
problem
給出一個1到n的全排列,現在對這個全排列序列進行m次區域性排序
排序分為兩種
1:(0,l,r)表示將區間[l,r]的數字升序排序
2:(1,l,r)表示將區間[l,r]的數字降序排序
最後詢問第q位置上的數字。
solution
考慮二分答案
對於mid
1.將所有 >= mid 的數變成 1, < mid 的數變成 0 (01排序不影響排序結果,得到相對的大小關係)
2.將處理過後的序列進行排序
如果 q 這個位置上最後是 0 ,則 ans < mid ,我們就去找更小的值
如果 q 這個位置上最後是 1, 則 ans >= mid,我們就去找更大的值
這樣原題就變成了01序列排序,可以用線段樹logn維護
假如說將 [l, r] 這段升序排列,
算出 sum = find(l, r) 即 [l, r] 中 1 的個數
維護排序的操作:
change(r - sum + 1, r, 1); change(l, r - sum, 0);
codes
#include<cstdio>
const int maxn = 100010;
#define lch o<<1
#define rch o<<1|1
int _a[maxn], sgt[maxn<<2], tag[maxn<<2];
void build(int o, int l, int r){
tag[o] = -1;
if(l == r){
sgt[o] = _a[l];
return ;
}
int mid = l+r>>1;
build(lch,l,mid); build(rch,mid+1,r);
sgt[o] = sgt[lch]+sgt[rch];
}
int pushdown(int o, int l, int r){
if(tag[o] != -1){
int mid = l+r>>1;
sgt[lch] = (mid-l+1)*tag[o];
sgt[rch] = (r-mid)*tag[o];
tag[lch] = tag[rch] = tag[o];
tag[o] = -1;
}
}
int query(int o, int l, int r, int L, int R){
if(r < L || l > R)return 0;
if(L <= l && r <= R)return sgt[o];
pushdown(o, l, r);
int mid = l+r>>1, ans = 0;
if(L <= mid)ans += query(lch, l, mid, L, R);
if(R > mid)ans += query(rch, mid+1, r, L, R);
return ans;
}
void change(int o, int l, int r, int L, int R, int v){
if(r < L || l > R)return ;
if(L <= l && r <= R){
sgt[o] = (r-l+1)*v; tag[o] = v;
return ;
}
pushdown(o,l,r);
int mid = l+r>>1;
if(L <= mid)change(lch, l, mid, L, R, v);
if(R > mid)change(rch, mid+1, r, L, R, v);
sgt[o] = sgt[lch]+sgt[rch];
}
int n, m, a[maxn], op[maxn], x[maxn], y[maxn], pos;
int check(int _x){
for(int i = 1; i <= n; i++)
_a[i] = a[i]>=_x;
build(1,1,n);
for(int i = 1; i <= m; i++){
int t = query(1,1,n,x[i],y[i]);
if(op[i])change(1,1,n,x[i],x[i]+t-1,1),change(1,1,n,x[i]+t,y[i],0);
else change(1,1,n,x[i],y[i]-t,0), change(1,1,n,y[i]-t+1,y[i],1);
}
return query(1,1,n,pos,pos);
}
int main(){
scanf("%d%d",&n,&m);
for(int i = 1; i <= n; i++)scanf("%d",&a[i]);
for(int i = 1; i <= m; i++)scanf("%d%d%d",&op[i],&x[i],&y[i]);
scanf("%d", &pos);
int l = 1, r = n;
while(l < r){
int mid = l+r+1>>1;
if(check(mid))l = mid;
else r = mid-1;
}
printf("%d\n", l);
return 0;
}
相關文章
- bzoj4552: [Tjoi2016&Heoi2016]排序(二分+線段樹)排序
- 01 線段樹
- [HEOI2016/TJOI2016]排序-題解排序
- P2824 [HEOI2016/TJOI2016] 排序排序
- 01選擇排序排序
- 排序演算法:二分插入排序排序演算法
- 排序演算法之——二分插入排序演算法排序演算法
- LeetCode C++ 劍指 Offer 51. 陣列中的逆序對【歸併排序/樹狀陣列/線段樹】LeetCodeC++陣列排序
- 線~段~樹
- 線段樹
- 洛谷P4632 [APIO2018] New Home 新家(動態開節點線段樹 二分答案 掃描線 set)API
- 前端學習資料結構1 二分排序樹(BST)前端資料結構排序
- 2020.12.21-2020.12.27 leetcode刷題總結(拓撲排序&蓄水池抽樣&二叉搜尋樹&線段樹)LeetCode排序
- 線段樹模板
- 線段樹--RMQMQ
- 線段樹 hate it
- 【模版】線段樹
- 【Algorithm】二分排序小技巧Go排序
- 二叉排序樹 oj 2482排序
- js之排序二叉樹JS排序二叉樹
- ut.cpp 最大線段並減線段交 [線段樹]
- 排序:氣泡排序&快速排序排序
- 權值線段樹
- 線段樹筆記筆記
- Segment Tree(線段樹)
- 線段樹入門
- 李超線段樹
- 線段樹進階
- 折半查詢排序樹畫圖和排序
- Trie樹:字串頻率統計排序字串排序
- 排序二叉樹和平衡二叉樹排序二叉樹
- 希爾排序使用直接插入排序、二分插入排序的C++程式碼實現演算法排序C++演算法
- php插入排序,快速排序,歸併排序,堆排序PHP排序
- 【排序】插入類排序—(折半)插入排序、希爾排序排序
- 排序演算法(氣泡排序,選擇排序,插入排序,希爾排序)排序演算法
- 【2024-ZR-C Day 2】資料結構(1):線段樹上二分資料結構
- 洛谷題單指南-線段樹-P3373 【模板】線段樹 2
- 順序表實現二分排序排序