DLUT 1201: 区间游戏

Description

 小Q在埃森哲工作想来也有日子了,表现非常突出,这不,最近team leader刚指派他带新来的小Y。

小Q总能在生活中找到游戏的乐趣,今天他决定跟小Y对一个区间集合进行游戏。
已知现在有一个包含N个区间的集合P = {[Li, Ri] 1 <= i <= N}。小Q首先选择一个区间[Li, Ri],然后她将所有满足(Li < Lj && Rj < Ri)的区间j从P集合中拿走组成一个新的集合A。
小Y作为后手,将在A集合中选择一个区间[Lu, Ru],并将A区间中所有满足(Lu < Lv && Rv < Ru)的区间v拿走组成一个新的区间B。游戏只进行一轮。
小Q希望游戏结束后|A| - |B|越大越好,而小Y则希望|B| - |A|越大越好。假设现在两人都使用最优策略,则最终|A| - |B|的值是多少?

Input

 多组测试数据。

第1行:一个整数N(1 <= N <= 100,000)。
第2到N+1行:每行输入两个整数Li, Ri(0 <= Li <= Ri <= 1,000,000,000)。

Output

 对于每组数据输出一行,包含一个整数,代表最终|A| - |B|的值。

Sample Input

41 52 43 33 3

Sample Output

2

HINT

 |A|表示A集合中元素的个数。


如果,Alice选择[2, 4],则A = {[3, 3], [3, 3]},Bob在A集合中不管选谁,都只能得到空集,结果为2。

如果,Alice选择[1, 5], 则A = {[2, 4], [3, 3], [3, 3]},Bob选择[2, 4],则A = {[2, 4]}, B = {[3, 3], [3, 3]},结果为-1。

解题思路:要求求|A|-|B|的值,其实当你确定A区间后,|A|-|B|已经确定了。
     1)先离散化输入的区间值,将结果保存在数组a中,然后排序,剔除a里面重复元素;
     2)将输入的区间按右边界从小到大排序,如果右边界相等,按左边界从小到大排;
     3)从a数组里面找到区间边界值,并将其更换为在a里面的序号;
     4)经过以上处理后,扫描所有区间,应为区间已按右边界值排序,所以从左边扫描时
   只需要统计比该区间左边界大的区间,得到的就是|A|,因为数据很大所以需要用树状    数组,|B|是在求完根据|A|后不断更新的;
说明:参考以下大神代码写的:大神博客链接,
#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <string.h>
using namespace std;

#define M 100100
#define lowbit(x) (x&(-x))

struct Node
{
    int l, r;
    bool operator < (const Node &t) const
    {
        if(t.r==r) return l<t.l;
        return r<t.r;
    }
}node[M];

int a[M<<1];
int f[2][M<<1];

void update(int pos, int a)
{
    while(pos)
    {
        f[1][pos] = max(f[1][pos], a);
        f[0][pos] +=1;
        pos -= lowbit(pos);
    }
}

int solve(int pos, int &B)
{
    int rec;
    rec = B= 0;
    while(pos<=2*M)
    {
        rec += f[0][pos];
        B = max(B, f[1][pos]);
        pos += lowbit(pos);
    }
    return rec;
}

int main()
{
    int n;

    while(~scanf("%d", &n))
    {
        memset(f, 0, sizeof(f));
        int l = 0;
        for(int i=0; i<n; i++)
        {
            scanf("%d%d", &node[i].l, &node[i].r);
            a[l++] = node[i].l; a[l++] = node[i].r; //离散化
        }
        sort(a, a+l);
        sort(node, node+n);
        l = unique(a, a+l)-a;  //剔除a里面重复元素;

        for(int i=0; i<n; i++)
        {
            node[i].l = lower_bound(a, a+l, node[i].l)-a+1;  //求在a里面的对应序号;
            node[i].r = lower_bound(a, a+l, node[i].r)-a+1;
        }

        int ans = -1111111111;
        for(int i=0; i<n; i++)
        {
            int A, B;
            A = solve(node[i].l, B);   //计算A, B;
            ans = max(ans, (A-B-B));
            update(node[i].l-1, A);    //更新状态数组;
        }
        printf("%d\n", ans);
    }

    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值