HDU

来源:互联网 发布:java实现链表反转 编辑:程序博客网 时间:2024/06/14 15:31

传送门:HDU5493

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

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

代码:

#include<bits/stdc++.h>#define ll long long#define lson l, mid, rt << 1#define rson mid + 1, r, rt << 1 | 1using 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<bits/stdc++.h>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 x<key? 0:1;    }    void Maintain()    {        size=1;        if(ch[0]!=NULL) size+=ch[0]->size;        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效率稍微比线段树差一点,可能是要申请和释放空间的缘故。