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个军队

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

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

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

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

问是否能全歼敌军

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

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

(待补)

#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\n");
            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\n");
            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", n-ans);
    }

    return 0;
}
时间: 2024-09-29 00:05:36

2014上海区域赛 I题 Defeat the Enemy 离线读入 在线更新 线段树套优先队列的相关文章

刷题总结——二逼平衡树(bzoj3224线段树套splay)

题目: Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:1.查询k在区间内的排名2.查询区间内排名为k的值3.修改某一位值上的数值4.查询k在区间内的前驱(前驱定义为小于x,且最大的数)5.查询k在区间内的后继(后继定义为大于x,且最小的数) Input 第一行两个数 n,m 表示长度为n的有序序列和m个操作第二行有n个数,表示有序序列下面有m行,opt表示操作标号若opt=1 则为操作1,之后有三个数l,r,k 表示查询k在区间[l,r

(山东省第一届省赛 I 题) SDUTOJ 2159 Ivan comes again! (线段树+set)

题目地址:SDUT 2159 这题的数据很水..几乎所有人都是水过去的..网上也没找到正解,全是水过去的.于是我来第一发正解23333. 首先,可以想到的是先离线下来,然后对行离散化,然后对于每行的所有列用set去存,那么怎么去找最小的行有大于给出列的列数呢?这时候线段树就可以登场了,用线段树来维护每一行的出现的最大列,这样就可以用线段树去搜了.然后删除添加操作同时在set与线段树中完成. 代码如下: #include <iostream> #include <string.h>

HDOJ Osu! 5078【2014鞍山区域赛I题-水】

Osu! Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others) Total Submission(s): 1263    Accepted Submission(s): 660 Special Judge Problem Description Osu! is a very popular music game. Basically, it is a game about cli

ACM学习历程——ZOJ 3829 Known Notation (2014牡丹江区域赛K题)(策略,栈)

Description Do you know reverse Polish notation (RPN)? It is a known notation in the area of mathematics and computer science. It is also known as postfix notation since every operator in an expression follows all of its operands. Bob is a student in

hdu 5137 去掉一个点 使得最短路最大(2014广州区域赛K题)

题意:从2~n-1这几个点中任意去掉一个点,使得从1到n的最短路径最大,如果任意去掉一个点1~n无通路输出Inf. Sample Input4 51 2 31 3 71 4 502 3 43 4 23 21 2 302 3 100 0 Sample Output50Inf 1 # include <iostream> 2 # include <cstdio> 3 # include <cstring> 4 # include <algorithm> 5 #

ACM 2015年上海区域赛A题 HDU 5572An Easy Physics Problem

题意: 光滑平面,一个刚性小球,一个固定的刚性圆柱体 ,给定圆柱体圆心坐标,半径 ,小球起点坐标,起始运动方向(向量) ,终点坐标 ,问能否到达终点,小球运动中如果碰到圆柱体会反射. 学到了向量模板,写法简洁. 1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<iostream> 5 #define clc(a,b) sizeof(a,b,sizeof(a)) 6

UVALive 7148 LRIP 14年上海区域赛K题 树分治

题意 n个点组成一棵树, 带有点权. 求最长不降的路径的长度, 且路径上最大值最小值之差不超过D. 显然是树分治, 但是分治之后如何维护答案呢. 假设当前重心为g, 分别记录g出发不降路径的长度,以及最大值, 和不升路径的长度以及最小值. 这里用到一个map和二分, 线段树也可以, 但是如果用线段树还要考虑负值, 再加上线段树的clear以及稍微暴力的查询.  常数大小不好说. 1 #include <bits/stdc++.h> 2 using namespace std; 3 typede

CF GYM100548 (相邻格子颜色不同的方案数 2014西安区域赛F题 容斥原理)

n个格子排成一行,有m种颜色,问用恰好k种颜色进行染色,使得相邻格子颜色不同的方案数. integers n, m, k (1 ≤n, m ≤ 10^9, 1 ≤ k ≤ 10^6, k ≤ n, m). m种颜色取k种 C(m, k) 这个可以放最后乘 那么问题就变成只用k种颜色第一个格子有k种涂法 第二个有k-1种 第三个也是k-1种 一共就是k*(k-1)^(n-1) 这种算法仅保证了相邻颜色不同,总颜色数不超过k种,并没有保证恰好出现k种颜色 也就是多算了恰好出现2种 恰好出现3种...

ACM学习历程——ZOJ 3822 Domination (2014牡丹江区域赛 D题)(概率,数学递推)

Description Edward is the headmaster of Marjar University. He is enthusiastic about chess and often plays chess with his friends. What's more, he bought a large decorative chessboard with N rows and M columns. Every day after work, Edward will place