題目大意
給定乙個長度為n的序列,有m個操作,操作包括兩種: 0l
r 0lr
區間[l,r]的數字公升序排序 1l
r 1lr
區間[l,r]的數字降序排序
最後詢問在q位置上的數是多少?其中n
≤100000,m
≤100000
n
≤100000,m
≤100000
qwq這個題是看了題解才會的,感覺思路很不錯
我們考慮,這個題的詢問其實只有一組,所以我們可以 二分乙個最終在q的數是多少(或者說在原來的排名是多少)
每次將大於等於mi
d mid
的數變為1,小於的為0。
那麼對於公升序排序,假設這個區間有to
t tot
個1,
我們就可以將[r
−tot
+1,r
] [r−
tot+
1,r]
賦值為1,將剩餘區間賦值為0
而降序排序呢,我們就可以將[l
,l+t
ot−1
] [l,
l+to
t−1]
賦值為1,其餘為0
這樣就將「排序「 —->「區間賦值」:
那麼,我們不難想到!!!線段樹!!!
只需要最後我們看一下第q個數是不是1就可以,如果是1,我們可以稍微加大mid,不然就減少mid
上**
#include
#include
#include
#include
#include
#include
#include
#include
using
namespace
std;
inline
int read()
while (isdigit(ch))
return x*f;
}const
int maxn = 100100;
int f[4*maxn];
int add[4*maxn];
int n,m,a[maxn];
int x[maxn],y[maxn],z[maxn];
int c[maxn];
int l,r;
int ques;
void up(int root)
void pushdown(int root,int l,int r)
}void build(int root,int l,int r)
int mid =(l+r) >> 1;
build(2*root,l,mid);
build(2*root+1,mid+1,r);
up(root);
}void update(int root,int l,int r,int x,int y,int p)
pushdown(root,l,r);
int mid = (l+r) >> 1;
if (x<=mid) update(2*root,l,mid,x,y,p);
if (y>mid) update(2*root+1,mid+1,r,x,y,p);
up(root);
}int query(int root,int l,int r,int x,int y)
pushdown(root,l,r);
int mid = (l+r) >> 1;
int ans=0;
if (x<=mid) ans=ans+query(2*root,l,mid,x,y);
if (y>mid) ans=ans+query(2*root+1,mid+1,r,x,y);
return ans;
}bool check(int mid)
else
}if (query(1,1,n,ques,ques)==1) return
true;
else
false;
}int ans;
int main()
ques=read();
//二分這個位置上的數是多少
while (l<=r)
cout
0;}
BZOJ 4552 二分 線段樹 思維)
傳送門 此題是道好題!首先要跳出思維定勢,不是去想如何用資料結構去直接維護排序過程,而是嘗試二分a p 的值 設二分a p 的值為x 我們將大於x的數標記為1,小於等於x的數標記為0 則整個序列只由01組成,記為b 將乙個區間公升序排序,則相當於將1全部移到右邊,0全部移到左邊,降序排序反之 例 a...
二分排序(java)
基本思想就是 將待排序元素分成大小大致相同 的兩個子集合,分別 對兩個子集合進行排序,最終將排好序的子集合合併成所要求的排好序的集合。package com.suanfa 二分排序 author administrator public class merge 合併陣列 public void co...
演算法 二分排序
二分排序這個詞是我在面試中遇到的,當時第一反應是二分查詢,然後被打斷,是二分排序演算法,最終才了解到,二分排序就是我們熟知的歸併排序。它又稱二路排序。首先說一下歸併的思想 先將一組數列,數列中含有n個元素,假設將每乙個元素看成是乙個有序的數列,就是n個有序的子串行,每個子串行的長度為1,然後倆倆合併...