bzoj 4552 [Tjoi2016&Heoi2016]排序 (二分答案 线段树)
Posted kls123
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj 4552 [Tjoi2016&Heoi2016]排序 (二分答案 线段树)相关的知识,希望对你有一定的参考价值。
题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=4552
题意:
给你一个1-n的全排列,m次操作,操作由两种:1.将[l,r]升序排序,2.将[l,r]降序排列
最后给你一个点p,输出这个点的数
思路:
因为这道题只有一个询问,只需要知道一个位置的值,且序列是全排列,那么我们可以对答案进行二分,首先我们先选定一个值x,将数组中比x大的全部变成1,小于等于x的变为0,然后用线段树去模拟排序的操作,最后我们需要查询p位置的数如果为1那么代表答案大于当前数x,为0代表答案小于当前数x,继续二分就好了
实现代码:
#include<bits/stdc++.h> using namespace std; #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define mid int m = (l + r) >> 1 const int M = 1e5 +10; int sum[M<<2],flag[M<<2],lazy[M<<2],a[M],b[M],op[M]; struct node{ int l,r; }q[M]; void pushup(int rt){ sum[rt] = sum[rt<<1] + sum[rt<<1|1]; } void pushdown(int l,int r,int rt){ if(flag[rt]){ mid; sum[rt<<1] = lazy[rt]*(m-l+1); sum[rt<<1|1] = lazy[rt]*(r-m); lazy[rt<<1] = lazy[rt<<1|1] = lazy[rt]; flag[rt<<1] = flag[rt<<1|1] = flag[rt]; flag[rt] = 0; } } void build(int l,int r,int rt){ flag[rt] = 0; lazy[rt] = 0; if(l == r){ sum[rt] = b[l]; return; } mid; build(lson); build(rson); pushup(rt); } void update(int L,int R,int c,int l,int r,int rt){ if(L <= l&&R >= r){ sum[rt] = c*(r-l+1); lazy[rt] = c; flag[rt] = 1; return ; } pushdown(l,r,rt); mid; if(L <= m) update(L,R,c,lson); if(R > m) update(L,R,c,rson); pushup(rt); } int query(int L,int R,int l,int r,int rt){ if(L <= l&&R >= r){ return sum[rt]; } pushdown(l,r,rt); mid; int ret = 0; if(L <= m) ret += query(L,R,lson); if(R > m) ret += query(L,R,rson); return ret ; } int main() { int n,k,pos; scanf("%d%d",&n,&k); for(int i = 1;i <= n;i ++) scanf("%d",&a[i]); for(int i = 1;i <= k;i ++) scanf("%d%d%d",&op[i],&q[i].l,&q[i].r); scanf("%d",&pos); int l = 1,r = n; while(l < r){ mid; for(int i = 1;i <= n;i ++){ if(a[i] > m) b[i] = 1; else b[i] = 0; } build(1,n,1); for(int i = 1;i <= k;i ++){ int cnt = query(q[i].l,q[i].r,1,n,1); if(op[i]){ //降序排列,1放在前面,0放在后面 if(cnt) update(q[i].l,q[i].l+cnt-1,1,1,n,1); if(cnt+q[i].l <= q[i].r) update(q[i].l+cnt,q[i].r,0,1,n,1); } else{ //升序排序,1放在后面,0放在前面 if(cnt) update(q[i].r-cnt+1,q[i].r,1,1,n,1); if(q[i].r-cnt >= q[i].l) update(q[i].l,q[i].r-cnt,0,1,n,1); } } if(query(pos,pos,1,n,1)) l = m+1; else r = m; } printf("%d ",l); return 0; }
以上是关于bzoj 4552 [Tjoi2016&Heoi2016]排序 (二分答案 线段树)的主要内容,如果未能解决你的问题,请参考以下文章
BZOJ 4552: [Tjoi2016&Heoi2016]排序
[BZOJ4552][TJOI2016&&HEOI2016]排序
BZOJ4552:[Tjoi2016&Heoi2016]排序
[BZOJ] 4552: [Tjoi2016&Heoi2016]排序 #二分+线段树+算法设计策略