1. 程式人生 > >bzoj4552: [Tjoi2016&Heoi2016]排序(二分+線段樹)

bzoj4552: [Tjoi2016&Heoi2016]排序(二分+線段樹)

pre algo 說明 size getchar() lib pla using 如何

  又是久違的1A哇...

  好喵喵的題!二分a[p],把大於mid的數改為1,小於等於mid的數改為0,變成01串後就可以用線段樹進行那一連串排序了,排序後如果p的位置上的數為0,說明答案比mid小,如果為1,說明答案比mid大。

  如何理解呢?我們的目的其實是讓比a[p]大的數都為1,這樣子p位置上剛好為0。如果p位置上為1,說明mid較小,a[p]>mid,把a[p]給標記成了1。如果p位置上為0,就是把a[p]<=mid,把a[p]標記成了0,但是這樣還有一些大於a[p]的位置也是0,所以繼續往小的地方逼近答案。

技術分享
#include<iostream> 
#include
<cstring> #include<cstdlib> #include<cstdio> #include<cmath> #include<algorithm> using namespace std; const int maxn=500010,inf=1e9; struct poi{int sum,tag;}tree[maxn]; int n,m,q; int a[maxn],b[maxn],l[maxn],r[maxn],ty[maxn]; inline void read(int &k) {
int f=1;k=0;char c=getchar(); while(c<0||c>9)c==-&&(f=-1),c=getchar(); while(c<=9&&c>=0)k=k*10+c-0,c=getchar(); k*=f; } inline void pushup(int x){tree[x].sum=tree[x<<1].sum+tree[x<<1|1].sum;} inline void pushdown(int x,int l,int r) {
if(tree[x].tag==-1)return; int mid=(l+r)>>1; if(tree[x].tag==1) { tree[x<<1].sum=mid-l+1;tree[x<<1].tag=1; tree[x<<1|1].sum=r-mid;tree[x<<1|1].tag=1; } else tree[x<<1].sum=tree[x<<1|1].sum=tree[x<<1].tag=tree[x<<1|1].tag=0; tree[x].tag=-1; } void build(int x,int l,int r) { tree[x].tag=-1; if(l==r){tree[x].sum=b[l];return;} int mid=(l+r)>>1; build(x<<1,l,mid);build(x<<1|1,mid+1,r); pushup(x); } void update(int x,int l,int r,int cl,int cr,int ty) { if(cl<=l&&r<=cr){tree[x].sum=ty*(r-l+1);tree[x].tag=ty;return;} pushdown(x,l,r); int mid=(l+r)>>1; if(cl<=mid)update(x<<1,l,mid,cl,cr,ty); if(cr>mid)update(x<<1|1,mid+1,r,cl,cr,ty); pushup(x); } int query(int x,int l,int r,int cl,int cr) { if(cl<=l&&r<=cr)return tree[x].sum; pushdown(x,l,r); int mid=(l+r)>>1,ret=0; if(cl<=mid)ret+=query(x<<1,l,mid,cl,cr); if(cr>mid)ret+=query(x<<1|1,mid+1,r,cl,cr); return ret; } bool check(int x) { for(int i=1;i<=n;i++)b[i]=a[i]>x; build(1,1,n); for(int i=1;i<=m;i++) { int x=query(1,1,n,l[i],r[i]); if(ty[i]) { if(x)update(1,1,n,l[i],l[i]+x-1,1); if(l[i]+x<=r[i])update(1,1,n,l[i]+x,r[i],0); } else { if(l[i]<=r[i]-x)update(1,1,n,l[i],r[i]-x,0); if(x)update(1,1,n,r[i]-x+1,r[i],1); } } return !query(1,1,n,q,q); } int main() { read(n);read(m); for(int i=1;i<=n;i++)read(a[i]); for(int i=1;i<=m;i++)read(ty[i]),read(l[i]),read(r[i]); read(q); int l=1,r=n; while(l<r) { int mid=(l+r)>>1; if(check(mid))r=mid; else l=mid+1; } printf("%d",l); }
View Code

bzoj4552: [Tjoi2016&Heoi2016]排序(二分+線段樹)