在 2016 2016 2016 年,佳媛姐姐喜欢上了数字序列。因而她经常研究关于序列的一些奇奇怪怪的问题,现在她在研究一个难题,需要你来帮助她。
这个难题是这样子的:给出一个 1 1 1 到 n n n 的排列,现在对这个排列序列进行 m m m 次局部排序,排序分为两种:
0 l r
表示将区间 [ l , r ] [l,r] [l,r] 的数字升序排序1 l r
表示将区间 [ l , r ] [l,r] [l,r] 的数字降序排序注意,这里是对下标在区间 [ l , r ] [l,r] [l,r] 内的数排序。
最后询问第 q q q 位置上的数字。
输入数据的第一行为两个整数 n n n 和 m m m, n n n 表示序列的长度, m m m 表示局部排序的次数。
第二行为 n n n 个整数,表示 1 1 1 到 n n n 的一个排列。
接下来输入 m m m 行,每一行有三个整数 op , l , r \text{op},l,r op,l,r, op \text{op} op 为 0 0 0 代表升序排序, op \text{op} op 为 1 1 1 代表降序排序, l , r l,r l,r 表示排序的区间。
最后输入一个整数 q q q,表示排序完之后询问的位置
输出数据仅有一行,一个整数,表示按照顺序将全部的部分排序结束后第 q q q 位置上的数字。
6 3
1 6 2 5 3 4
0 1 4
1 3 6
0 2 4
3
5
河北省选2016第一天第二题。
对于 30 % 30\% 30% 的数据, n , m ≤ 1000 n,m\leq 1000 n,m≤1000
对于 100 % 100\% 100% 的数据, n , m ≤ 1 0 5 n,m\leq 10^5 n,m≤105, 1 ≤ q ≤ n 1\leq q\leq n 1≤q≤n
二分出答案,设为d,同时对原序列a进行修改: a i ≥ d , 使 b i = 1 , 其他为 0 a_i \ge d,使b_i = 1,其他为0 ai≥d,使bi=1,其他为0 几个问题:
#include
using namespace std;
const int M = 1e7+10;
#define int long long
struct node{
int op,l,r;
}qs[M];
istream& operator >> (istream& in,node& t){
in>>t.op>>t.l>>t.r;
return in;
}
int a[M];
int n,m,q;int maxn=0;
struct segment {
#define lc(p) (p<<1)
#define rc(p) ((p<<1)|1)
int tag[M << 2], sum[M << 2];
bool vis[M<<2];
void f(int o, int l, int r, int k) {
tag[o] = k;vis[o]=1;
sum[o] = k * (r - l + 1);
}
void push_up(int x) {
sum[x] = sum[lc(x)] + sum[rc(x)];
}
void push_down(int o, int l, int r) {
if (!vis[o]) return;
int mid = l + r >> 1;
f(lc(o), l, mid, tag[o]);
f(rc(o), mid + 1, r, tag[o]);
tag[o] = 0;vis[o]=0;
}
void build(int o, int l, int r,int k) {
vis[o]=0;
if (l == r) { sum[o] = a[l]>=k; return; }
int mid = l + r >> 1;
build(lc(o), l, mid,k);
build(rc(o), mid + 1, r,k);
push_up(o);
}
int query(int ql, int qr, int o, int l, int r) {
if(ql>r or qr<l)return 0;
if (ql <= l and r <= qr) return sum[o];
int ans = 0;
int mid = l + r >> 1;
push_down(o, l, r);
if (ql<=mid) ans += query(ql, qr, lc(o), l, mid);
if (mid+1<=qr) ans+=query(ql,qr,rc(o),mid+1,r);
push_up(o);
return ans;
}
void update(int ql,int qr,int o,int l,int r,int k){
if(ql>r or qr<l)return;
if(ql<=l and r<=qr) {f(o,l,r,k);return;}
push_down(o,l,r);
int mid = l + r >> 1;
if (ql<=mid) update(ql, qr, lc(o), l, mid,k);
if (mid+1<=qr) update(ql,qr,rc(o),mid+1,r,k);
push_up(o);
}
}t1;
void read(){
cin>>n>>m;
for (int i=1;i<=n;i++) cin>>a[i],maxn=max(maxn,a[i]);
for (int i=1;i<=m;i++) cin>>qs[i];
cin>>q;
}
bool check(int d){
t1.build(1,1,n,d);
int num;
for (int i=1;i<=m;i++){
num=t1.query(qs[i].l,qs[i].r,1,1,n);
if(qs[i].op) t1.update(qs[i].l,qs[i].l+num-1,1,1,n,1),t1.update(qs[i].l+num,qs[i].r,1,1,n,0);
else {
num=qs[i].r-qs[i].l+1-num;
t1.update(qs[i].l,qs[i].l+num-1,1,1,n,0),t1.update(qs[i].l+num,qs[i].r,1,1,n,1);
}
}
return t1.query(q,q,1,1,n);
}
void solve(){
int l=1,r=maxn,ans;
while(l<=r){
int mid=(l+r)>>1;
if (check(mid)) l=mid+1,ans=mid;
else r=mid-1;
}
cout<<ans;
}
signed main() {
read();
solve();
return 0;
}
只说check函数
bool check(int d){
t1.build(1,1,n,d);
int num;
for (int i=1;i<=m;i++){
num=t1.query(qs[i].l,qs[i].r,1,1,n);
if(qs[i].op) t1.update(qs[i].l,qs[i].l+num-1,1,1,n,1),t1.update(qs[i].l+num,qs[i].r,1,1,n,0);
else {
num=qs[i].r-qs[i].l+1-num;
t1.update(qs[i].l,qs[i].l+num-1,1,1,n,0),t1.update(qs[i].l+num,qs[i].r,1,1,n,1);
}
}
return t1.query(q,q,1,1,n);
}
对于操作1,2,只考虑1,0的个数即可
[ l , l + n u m − 1 ] = 1 , [ l + n u m , r ] = 0 [l,l+num-1]=1,[l+num,r]=0 [l,l+num−1]=1,[l+num,r]=0 — —降序排序
[ l , l + n u m − 1 ] = 0 , [ l + n u m , r ] = 1 [l,l+num-1]=0,[l+num,r]=1 [l,l+num−1]=0,[l+num,r]=1 — —升序排序