[HEOI2016/TJOI2016]排序
内存限制:256 MiB 时间限制:6000 ms 标准输入输出
题目类型:传统 评测方式:文本比较题目描述
输入格式
输出格式
样例
题解:
思路挺神仙的
这题你要是真的去排序就死了。。。
但我们还是要用到线段树
但和tree这道kruscal一样思路非常神奇
我们二分q位置上的数
每一次二分,维护一个线段树,
我们设当前分到的数是x,那么我们让所有大于等于x的叶节点为1,小于x为0
这样我们维护区间中有几个1,
如果升序排序我们就把前一段暴力改成1,后一段改成0,降序反过来
这样我们查询q位置是什么数
如果是1,则当前二分的x可能偏小,但可能就是答案,要用mid更新ans,因为我们是让大于等于x的节点为1,
如果是0,则说明当前x偏大,应查询较小的数
每次二分都这样检查一遍,二分结束的ans就是答案
反套路题,多多积累
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> #include<vector> #include<queue> #define int long long #define MAXN 100005 using namespace std; int n,m,a[MAXN],q,l,r,ans; struct node{ int opt,l,r; }ask[MAXN]; struct Segtree{ int l,r,val,laz; }tree[MAXN<<2]; void down(int k){ if(tree[k].laz==-1) return ; tree[k<<1].laz=tree[k].laz; tree[k<<1|1].laz=tree[k].laz; tree[k<<1].val=(tree[k<<1].r-tree[k<<1].l+1)*tree[k].laz; tree[k<<1|1].val=(tree[k<<1|1].r-tree[k<<1|1].l+1)*tree[k].laz; tree[k].laz=-1; } void build(int k,int l,int r,int x){ tree[k].l=l,tree[k].r=r; tree[k].laz=-1; if(l==r){ if(a[l]>=x) tree[k].val=1; else tree[k].val=0; return ; } int mid=(l+r)>>1; build(k<<1,l,mid,x); build(k<<1|1,mid+1,r,x); tree[k].val=tree[k<<1].val+tree[k<<1|1].val; } int query(int k,int opl,int opr){ int l=tree[k].l,r=tree[k].r; if(opl<=l&&r<=opr){ return tree[k].val; } down(k); int mid=(l+r)>>1; if(opr<=mid) return query(k<<1,opl,opr); if(opl>mid) return query(k<<1|1,opl,opr); return query(k<<1,opl,mid)+query(k<<1|1,mid+1,opr); } void change(int k,int opl,int opr,int val){ int l=tree[k].l,r=tree[k].r; if(opl<=l&&r<=opr){ tree[k].val=(r-l+1)*val; tree[k].laz=val; return ; } down(k); int mid=(l+r)>>1; if(opr<=mid) change(k<<1,opl,opr,val); else if(opl>mid) change(k<<1|1,opl,opr,val); else{ change(k<<1,opl,opr,val); change(k<<1|1,opl,opr,val); } tree[k].val=tree[k<<1].val+tree[k<<1|1].val; } bool check(int x){ build(1,1,n,x); for(int i=1;i<=m;i++){ int sum=query(1,ask[i].l,ask[i].r); if(sum==0||sum==ask[i].r-ask[i].l+1) continue; if(!ask[i].opt){ change(1,ask[i].l,ask[i].r-sum,0); change(1,ask[i].r-sum+1,ask[i].r,1); }else{ change(1,ask[i].l,ask[i].l+sum-1,1); change(1,ask[i].l+sum,ask[i].r,0); } } return query(1,q,q); } signed main(){ scanf("%lld%lld",&n,&m); for(int i=1;i<=n;i++) scanf("%lld",&a[i]); for(int i=1;i<=m;i++){ scanf("%lld%lld%lld",&ask[i].opt,&ask[i].l,&ask[i].r); } scanf("%lld",&q); l=1,r=n; while(l<=r){ int mid=(l+r)>>1; if(check(mid)) ans=mid,l=mid+1; else r=mid-1; } printf("%lld ",ans); return 0; }