P2824 [HEOI2016/TJOI2016]排序
【题意】给序列局部排序,问最终排序完成的q位置
【分析】考虑暴力,每次都sort修改局部排序部分,时间复杂度为O(nmlogn)
观察到题目只求q一个位置上的值,所以我们可以对这个答案进行二分,然后把序列根据比mid大/小来转换成0/1
对于0/1的排序,我们可以用线段树计算排序区间l,r的1的个数(也就是sum),如果排成升序然后把后面的改成1,前面的改成0即可
对于二分的每次judge都按照操作计算一遍,看q位是0还是1表示答案大了还是小了
【代码】
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> using namespace std; const int maxn=1e5+5; int n,m,q,op[maxn],l[maxn],r[maxn]; int a[maxn],b[maxn]; struct segtree { int l,r,sum,lz; }tr[maxn<<2]; #define lson now<<1 #define rson now<<1|1 void fuzhi(int now,int val) { tr[now].sum=(tr[now].r-tr[now].l+1)*val; tr[now].lz=val; } void pushdown(int now) { if(tr[now].lz==-1) return; fuzhi(lson,tr[now].lz); fuzhi(rson,tr[now].lz); tr[now].lz=-1; } void pushup(int now) { tr[now].sum=tr[lson].sum+tr[rson].sum; } void build(int now,int l,int r) { tr[now].l=l; tr[now].r=r; if(l==r) { tr[now].sum=b[l]; return; } int mid=l+r>>1; build(lson,l,mid); build(rson,mid+1,r); pushup(now); } int query(int now,int l,int r) { if(tr[now].l>=l && tr[now].r<=r) { return tr[now].sum; } int res=0; int mid=tr[now].l+tr[now].r>>1; pushdown(now); if(l<=mid) res+=query(lson,l,r); if(mid<r) res+=query(rson,l,r); return res; } void modify(int now,int l,int r,int val) { if(tr[now].l>=l && tr[now].r<=r) { tr[now].sum=(tr[now].r-tr[now].l+1)*val; tr[now].lz=val; return; } int mid=tr[now].l+tr[now].r>>1; pushdown(now); if(l<=mid) modify(lson,l,r,val); if(mid<r) modify(rson,l,r,val); pushup(now); } bool check(int x) { for(int i=1;i<=n*4;i++) tr[i].sum=0,tr[i].lz=-1; for(int i=1;i<=n;i++) b[i]=(a[i]>=x); build(1,1,n); for(int i=1;i<=m;i++) { int cntt=query(1,l[i],r[i]); if(!op[i]) { modify(1,l[i],r[i]-cntt,0); modify(1,r[i]-cntt+1,r[i],1); } else { modify(1,l[i],l[i]+cntt-1,1); modify(1,l[i]+cntt,r[i],0); } } int cnt=query(1,q,q); return cnt; } int main() { freopen("array.in","r",stdin); freopen("array.out","w",stdout); 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],&l[i],&r[i]); scanf("%d",&q); int L=1,R=n,ans=0; while(L<=R) { int mid=L+R>>1; if(check(mid)) L=mid+1,ans=mid; else R=mid-1; } printf("%d",ans); return 0; }