1. 程式人生 > 實用技巧 >牛客:CBX and children(平衡樹+二分+貪心)

牛客:CBX and children(平衡樹+二分+貪心)

題意:

眾所周知,CBX是一個非常喜歡和孩子們玩耍的男孩。一天,CBX和n個孩子在玩捉迷藏遊戲操場。每孩子有一個身高(整數),每個孩子都可以躲在另一個孩子的後面,前提是他後面的孩子至少是他身後孩子的兩倍。

每個孩子只能躲在一個孩子的後面,而躲在其他孩子的後面不能隱藏孩子。

假設躲在其他人後面的孩子不會被CBX看到,找到一個計劃,讓CBX看到最少的孩子

題解;

有一個顯然的貪心思路是,每次選取大於等於x*2的最小的那個人,把x放在他的後面。但是這樣好像無法保證正確性,再在這個基礎上二分答案。

具體做法是:每次選取mid個人作為可以被看到的,對於剩下的人,找到大於等於他的身高的兩倍的最矮的被看到的人作為遮擋,最後看看能否擋住剩下的所有人。

二分內check這個過程很多資料結構都可以實現,這裡我使用的是Treap樹。

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+100;
const int inf=1e9;
//treap樹
//利用BST的性質做查詢和修改
//利用隨機和堆優先順序來保持平衡
struct Treap_tree {
    int ch[2];
    int v;
    int dat;//優先順序 
    int size;//子樹節點數 
    int cnt;//重複數 
}t[maxn];
int tot;
int root;
int newNode (int v) { tot++; t[tot].v=v; t[tot].dat=rand();//隨機優先順序 t[tot].size=1; t[tot].cnt=1; t[tot].ch[0]=0; t[tot].ch[1]=0; return tot; } void pushup (int x) { t[x].size=t[t[x].ch[0]].size+t[t[x].ch[1]].size+t[x].cnt; } void build () { root=newNode(-inf); t[root].ch[
1]=newNode(inf); pushup(root); } void rotate (int &id,int d) { int tt=t[id].ch[d^1]; t[id].ch[d^1]=t[tt].ch[d]; t[tt].ch[d]=id; id=tt; pushup(t[id].ch[d]); pushup(id); } void ins (int &id,int v) { if (!id) { id=newNode(v); return; } if (v==t[id].v) t[id].cnt++; else { ins(t[id].ch[v>t[id].v],v); if (t[id].dat<t[t[id].ch[v>t[id].v]].dat) rotate(id,v<t[id].v); } pushup(id); } void remove (int &id,int v) { if (!id) return; if (v==t[id].v) { if (t[id].cnt>1) { t[id].cnt--; pushup(id); return; } if (t[id].ch[0]||t[id].ch[1]) { if (!t[id].ch[1]||t[t[id].ch[0]].dat>t[t[id].ch[1]].dat) { rotate(id,1); remove(t[id].ch[1],v); } else { rotate(id,0); remove(t[id].ch[0],v); } pushup(id); } else id=0; return; } remove(t[id].ch[v>t[id].v],v); pushup(id); } int rk (int id,int v) { if (!id) return 0; if (v==t[id].v) return t[t[id].ch[0]].size+1; else if (v<t[id].v) return rk(t[id].ch[0],v); else return t[t[id].ch[0]].size+t[id].cnt+rk(t[id].ch[1],v); } int kth (int id,int k) { if (!id) return inf; if (k<=t[t[id].ch[0]].size) return kth(t[id].ch[0],k); else if (k<=t[t[id].ch[0]].size+t[id].cnt) return t[id].v; else return kth(t[id].ch[1],k-t[t[id].ch[0]].size-t[id].cnt); } int get_pre (int id,int v) { int pre; while (id) { if (t[id].v<v) pre=t[id].v,id=t[id].ch[1]; else id=t[id].ch[0]; } return pre; } int get_next (int id,int v) { int nxt; while (id) { if (t[id].v>v) nxt=t[id].v,id=t[id].ch[0]; else id=t[id].ch[1]; } return nxt; } int a[maxn]; int main () { int n; scanf("%d",&n); for (int i=1;i<=n;i++) scanf("%d",a+i); sort(a+1,a+n+1); int ans=-1; int l=1,r=n; while (l<=r) { int mid=(l+r)>>1; tot=0; build(); for (int i=n;i>n-mid;i--) ins(root,a[i]); int tt=mid; for (int i=1;i<=n-mid;i++) { int nxt=get_next(root,a[i]*2-1); if (nxt==inf) continue; tt++; remove(root,nxt); } if (tt==n) { ans=mid; r=mid-1; } else { l=mid+1; } } printf("%d\n",ans); }