zoukankan      html  css  js  c++  java
  • 2014上海区域赛 I题 Defeat the Enemy 离线读入 在线更新 线段树套优先队列

    题目链接:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=5158

    UVALive 7146

    题意

    自己有n个军队 敌方有m个军队

    每个军队都有攻击力和防守力两种属性

    当一方的攻击力>=对方的防御力时 可以把对方杀掉

    在一次战斗中有可能出现双方都死了或者双方都没死的情况

    另外要求己方不能有两只不同军队跟对方的同一只军队交战

    问是否能全歼敌军

    如果可以的话,输出最多可以存活多少只己方军队

    我们队的做法稍微有点复杂,我尽量解释得清楚一点:

    a数组存己方军队,b数组存地方军队

    先把a[]按防御力升序排,把b[]按攻击力升序排

    然后分别给b[]、a[]数组赋一个编号值ID

    b[i].ID = b[i]的攻击力在b[]中是第几弱 + 1

    a[i].ID = 能跟b[]中攻击力第(ID - 1)弱的打完不死的【此处不保证能杀掉对方】(攻击力相同的只计一次)

    如果跟谁打都死 那么ID = 1

    eg: 若ID = 3,那么他能跟b[]中攻击力第二弱(攻击力是次小值)

    每个ID会分到一个堆,是关于防御力的小根堆

    然后再把a[]按攻击力降序排,把b[]按防守力降序排

    这时候最外层循环是b[]中的军队

    每次把a[]中能打败b[i]的军队对应的优先队列并插入

    等把所有能打败b[i]的军队插入以后,此时所有优先队列中的所有a[]都是能杀掉b[i]的

    (之前插入的a[?]攻击力更高,所以更能杀掉b[i])

    此时要从中分配一个a[?]去打b[i]

    如果有可能有军队可以杀完b[i]后活下来,那么要选ID >= b[i].ID并且防御力最少的,这样残血活下来最经济

    如果谁去都是死,那么就找一个所有优先队列中防御力最低的去打即可

    关于a[]

    对于每个相同ID,之所以要采用堆,是因为要把每次询问的复杂度降到O(logn)

    对于不同的ID,如果采用优先队列数组,每次询问从头到尾扫一遍,每次查找都是O(n),那么整体就还是n方

    这时候要采用线段线段树

    每个叶子节点依次对应一个堆 然后其值为1时代表堆非空 0则表示堆空

    线段树记录区间和

    这样可以快速找到大于等于b[i].ID且堆非空的最小ID号,取出根节点即为应该与b[i]交战的军队

    如果找不到这样的ID号,就照大于等于1且堆非空的最小ID号

    如果还找不到,说明无解

    #include <iostream>
    #include <cstdlib>
    #include <cstdio>
    #include <algorithm>
    #include <iostream>
    #include <cstring>
    #include <cmath>
    #include <queue>
    
    using namespace std;
    
    typedef long long ll;
    
    const int maxn = 100000;
    
    struct Node{
        int A,D,ID;
    };
    
    priority_queue<int, vector<int>, greater<int> > que[maxn+10];
    
    struct tree{
        int l, r, data;
    }T[maxn*4];
    
    void buildTree(int now ,int l, int r)
    {
        int lson = now<<1, rson = lson|1;
        T[now].l = l; T[now].r = r;T[now].data = 0;
    
        if(l == r)
            return;
        int mid = (l+r)>>1;
        buildTree(lson, l, mid);
        buildTree(rson, mid+1, r);
    }
    
    void change(int now, int aim)
    {
        int lson = now<<1, rson = lson|1;
        if(T[now].l == aim && T[now].r == aim)
        {
            T[now].data ^= 1;
            return;
        }
        int mid = T[lson].r;
        if(aim <= mid)
            change(lson, aim);
        else
            change(rson, aim);
        T[now].data = T[lson].data+T[rson].data;
    }
    
    int getSum(int now, int index)
    {
        int lson = now<<1, rson = lson|1;
        if(T[now].r == index)
            return T[now].data;
        int mid = T[lson].r;
        if(index <= mid)
            return getSum(lson, index);
        else
            return T[lson].data+getSum(rson, index);
    }
    
    int findPos(int now, int aim)
    {
        int lson = now<<1, rson = lson|1;
        if(T[now].data < aim)
            return 0;
        if(T[now].l == T[now].r)
            return T[now].l;
        if(T[lson].data < aim)
            return findPos(rson, aim-T[lson].data);
        else
            return findPos(lson, aim);
    }
    
    bool cmpD(Node a, Node b)
    {
        return a.D<b.D;
    }
    bool cmpA(Node a, Node b)
    {
        return a.A<b.A;
    }
    
    Node a[maxn+10],b[maxn+10];
    
    void init(int cnt)
    {
        buildTree(1, 1, cnt);
        for(int i = 1; i <= cnt; i++)
            while(!que[i].empty()) que[i].pop();
    }
    int main()
    {
        //freopen("in2.txt", "r", stdin);
    
        int T;
        scanf("%d", &T);
        int kase = 0;
        while(T--)
        {
            int n,m;
            printf("Case #%d: ", ++kase);
            scanf("%d%d", &n, &m);
            for(int i = 0; i < n; i++)
                scanf("%d%d", &a[i].A, &a[i].D);
            for(int i = 0; i < m; i++)
                scanf("%d%d", &b[i].A, &b[i].D);
            if(m > n)
            {
                printf("-1
    ");
                continue;
            }
    
            sort(a,a+n,cmpD);
            sort(b,b+m,cmpA);
    
            int cnt = 2, cnta = 0;
            int ans = 0;
            for(int i = 0; i < m; i++)
            {
                b[i].ID = cnt;
                while(i < m-1 && b[i+1].A == b[i].A)  b[++i].ID = cnt;
                while(cnta < n && a[cnta].D <= b[i].A)
                    a[cnta++].ID = cnt-1;
                //if(cnta == n && i != m) {ans = -1;break;}
                cnt++;
            }
    
            for(int i = cnta; i < n; i++)
                a[i].ID = cnt-1;
    
            sort(a, a+n, cmpA);
            sort(b, b+m, cmpD);
            for(int i = n-1; m-n+i >= 0; i--)
                if(a[i].A < b[m-n+i].D)
                {
                    ans = -1;
                    break;
                }
    
            if(ans == -1)
            {
                printf("-1
    ");
                continue;
            }
            init(cnt);
            cnta = n-1;
            for(int i = m-1; i >= 0; i--)
            {
                while(a[cnta].A >= b[i].D && cnta >= 0)
                {
                    if(que[a[cnta].ID].empty())
                    {
                        change(1, a[cnta].ID);
                    }
                    que[a[cnta].ID].push(a[cnta].D);
                    cnta--;
                }
                int id = b[i].ID;
                int sum = getSum(1, id-1);
                int index = findPos(1, sum+1);
                if(index == 0)
                {
                    ans++;
                    int tmp = 1;
                    int ind = findPos(1,1);
                    que[ind].pop();
                    if(que[ind].empty())
                        change(1, ind);
                }
                else
                {
                    que[index].pop();
                    if(que[index].empty())
                        change(1, index);
                }
            }
            printf("%d
    ", n-ans);
        }
    
        return 0;
    }
  • 相关阅读:
    诊断Oracle 服从成绩
    联机热备份失踪败后,怎样翻开数据库?
    Oracle 8.0.4 for Windows NT的装配
    Oracle常用数据字典
    怎样快速查出Oracle数据库中的锁等待
    Oracle不凡包
    Developer/2000 R2.1 中文版 在 Windows NT 上的安置
    Oracle中巧用FORMS_DDL
    Oracle 基本常识
    autorun的执行的命令行
  • 原文地址:https://www.cnblogs.com/dishu/p/4529783.html
Copyright © 2011-2022 走看看