HDU - 5493 Queue 线段树 || Treap

传送门:HDU5493

题意:给出n个人的身高和每个人前面或者后面有多少人比他高(不知道是前面还是后面),问能否构造出一个合法的序列。

思路1:将所有人按身高从小到大排序,然后一个个取出来插入线段树,插入线段树的时候要保证前面留出足够的空来给比他高的人,又因为要字典序最小,那么我们插入的位置就是要min(ki, n - i - ki - 1) + 1.

代码:

#include
#define ll long long
#define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1 | 1
using namespace std;
const int MAXN = 100010;
struct node{
    int h, k;
    bool operator < (node a) const{
        return h < a.h;
    }
}p[MAXN];
int tree[MAXN << 2], ans[MAXN];
void build(int l, int r, int rt)
{
    if(l == r){
        tree[rt] = 1;
        return ;
    }
    int mid = (l + r) >> 1;
    build(lson);
    build(rson);
    tree[rt] = tree[rt << 1] + tree[rt << 1 | 1];
}
void update(int x, int val, int l, int r, int rt)
{
    if(l == r)
    {
        ans[l] = val;
        tree[rt] = 0;
        return ;
    }
    int mid = (l + r) >> 1;
    if(x >= tree[rt << 1]) update(x - tree[rt << 1], val, rson);
    else update(x, val, lson);
    tree[rt] = tree[rt << 1] + tree[rt << 1 | 1];
}
int main()
{
    int T, n, kase = 1;
    cin >> T;
    while(T--)
    {
       scanf("%d", &n);
       build(1, n, 1);
       for(int i = 0; i < n; i++)
       scanf("%d %d", &p[i].h, &p[i].k);
       sort(p, p + n);
       bool ok = 1;
       for(int i = 0; i < n; i++)
       {
           if(n - i - p[i].k <= 0){
                ok = 0;
                break;
           }
           update(min(p[i].k, n - i - p[i].k - 1), p[i].h, 1, n, 1);//前面留min()个空位置
       }
       printf("Case #%d: ", kase++);
       if(!ok){
            cout << "impossible\n";
            continue;
       }
       for(int i = 1; i <= n; i++)
       printf("%d%c", ans[i], " \n"[i == n]);
    }
}
思路2:将所有人身高按从大到小排序,每次取出一个人来插入Treap中,Treap维护已经构造出来的序列,那么新加的人插入的位置就是min(ki, x - ki) + 1。

Treap学习及模板:点击打开链接

代码:

#include
using namespace std;
const int MAXN = 100010;
struct Treap
{
    int size;
    int key,fix;
    Treap *ch[2];
    Treap(int key)
    {
        size=1;
        fix=rand();
        this->key=key;
        ch[0]=ch[1]=NULL;
    }
    int compare(int x) const
    {
        if(x==key) return -1;
        return xsize;
        if(ch[1]!=NULL) size+=ch[1]->size;
    }
};
void Rotate(Treap* &t,int d)
{
    Treap *k=t->ch[d^1];
    t->ch[d^1]=k->ch[d];
    k->ch[d]=t;
    t->Maintain();  
    k->Maintain();
    t=k;
}
void Insert(Treap* &t,int pos, int val)
{
    if(t==NULL) t=new Treap(val);
    else
    {
        int d;
    	if(pos <= (t->ch[0] ? t->ch[0]->size : 0)) d = 0;
    	else {
    		d = 1; pos = pos - (t->ch[0] ? t->ch[0]->size : 0) - 1;//注意这里,每个子树的下标都是从零开始的,因此进入右子树时下标要-1 
    	}
        Insert(t->ch[d], pos, val);
        if(t->ch[d]->fix > t->fix)
            Rotate(t, d^1);
    }
    t->Maintain();
}
void Print(Treap *t)
{
    if(t==NULL) return;
    Print(t->ch[0]);
    printf(" %d", t->key); 
    Print(t->ch[1]);
    delete t;//本题要注意在这里释放空间 
}
struct node{
	int h, k;
	bool operator < (node a) const{
		return h > a.h;
	}
}p[MAXN];
int main()
{
    int T, n, kase = 1;
    cin >> T;
    while(T--)
    {
    	scanf("%d", &n); 
	    for(int i = 0; i < n; i++)
	    scanf("%d %d", &p[i].h, &p[i].k);
	    sort(p, p + n);
	    Treap *root = NULL;
	    bool ok = 1;
	    for(int i = 0; i < n; i++)
	    {
	    	int pos = min(p[i].k, i - p[i].k);
			if(pos < 0){
				ok = 0; break;
			}
			Insert(root, pos, p[i].h);
	    }
	    printf("Case #%d:", kase++);
	    if(!ok)puts(" impossible");
	    else Print(root), puts("");
    }
    return 0;
}

Treap效率稍微比线段树差一点,可能是要申请和释放空间的缘故。


你可能感兴趣的:(hdu,线段树&&BIT&&平方分割)