BZOJ 4552 二分 線段樹 思維)

2021-08-26 08:55:58 字數 1709 閱讀 9967

傳送門

此題是道好題!

首先要跳出思維定勢,不是去想如何用資料結構去直接維護排序過程,而是嘗試二分a[p]的值

設二分a[p]的值為x

我們將大於x的數標記為1,小於等於x的數標記為0

則整個序列只由01組成,記為b

將乙個區間公升序排序,則相當於將1全部移到右邊,0全部移到左邊,降序排序反之

例: a=.x=4

標記後的序列b為

此時對[1,5]進行公升序排序,a=

標記後的序列b為

因此可以用線段樹維護標記後的序列,直接區間求和得到1的個數,再區間更新即可

如果排完序後b[p]=0,則說明a[p]<=x,繼續減小x

否則增大x

#include

#include

#include

#include

#define maxn 100005

using namespace std;

int n,m,qa;

struct node

} tree[maxn<<2];

int a[maxn];

struct sort_seg q[maxn];

void push_up(int

pos)

void build(int l,int r,int

pos,int middle)

int mid=(tree[pos].l+tree[pos].r)>>1;

build(l,mid,pos

<<1,middle);

build(mid+1,r,pos

<<1|1, middle);

push_up(pos);

}void push_down(int

pos)

}void update(int l,int r,int v,int

pos)

push_down(pos);

int mid=(tree[pos].l+tree[pos].r)>>1;

if(l<=mid) update(l,r,v,pos

<<1);

if(r>mid) update(l,r,v,pos

<<1|1);

push_up(pos);

}int query(int l,int r,int

pos)

push_down(pos);

int mid=(tree[pos].l+tree[pos].r)>>1;

int ans=0;

if(l<=mid) ans+=query(l,r,pos

<<1);

if(r>mid) ans+=query(l,r,pos

<<1|1);

return ans;

}int check(int

x) else

}if(query(qa,qa,1)==1) return

0; else

return1;}

int main()

for(int i=1; i<=m; i++)

int l=1,r=n;

int ans=n+1;

scanf("%d",&qa);

while(l<=r) else

}printf("%d\n",ans);

}

bzoj4552排序(線段樹,二分)

題目大意 給定乙個長度為n的序列,有m個操作,操作包括兩種 0l r 0lr 區間 l,r 的數字公升序排序 1l r 1lr 區間 l,r 的數字降序排序 最後詢問在q位置上的數是多少?其中n 100000,m 100000 n 100000,m 100000 qwq這個題是看了題解才會的,感覺思...

b vj K th Number(二分 線段樹)

有乙個數列a 1 n 中 數字各不相同 輸入m行i,j,k,目的是求a i.j 之間第k小的數 includeusing namespace std typedef long long ll const int n 1e6 5 ll n,m,a n vectort n void pushup int...

hdu4614 二分 線段樹

題意 給你1 n的花瓶 剛開始全是空的,現在有兩種操作,1 從花瓶a開始插入b朵花 如果不能插進去 輸出字串 否則輸出最多插入的起點和終點 結構體陣列num i 表示節點i空瓶的數目 線段樹 開始deal函式對整個樹初始化,update 更新函式 find 查詢區間有多少個空瓶 對於操作1 關鍵點是...