Codeforces Round #613 (Div. 2) Delete a Segment(删除一条边,计算并区间最大数量)

E. Delete a Segment

There are nn segments on a OxOx axis [l1,r1][l1,r1], [l2,r2][l2,r2], ..., [ln,rn][ln,rn]. Segment [l,r][l,r] covers all points from ll to rr inclusive, so all xx such that l≤x≤rl≤x≤r.

Segments can be placed arbitrarily  — be inside each other, coincide and so on. Segments can degenerate into points, that is li=rili=ri is possible.

Union of the set of segments is such a set of segments which covers exactly the same set of points as the original set. For example:

  • if n=3n=3 and there are segments [3,6][3,6], [100,100][100,100], [5,8][5,8] then their union is 22 segments: [3,8][3,8] and [100,100][100,100];
  • if n=5n=5 and there are segments [1,2][1,2], [2,3][2,3], [4,5][4,5], [4,6][4,6], [6,6][6,6] then their union is 22 segments: [1,3][1,3] and [4,6][4,6].

Obviously, a union is a set of pairwise non-intersecting segments.

You are asked to erase exactly one segment of the given nn so that the number of segments in the union of the rest n−1n−1 segments is maximum possible.

For example, if n=4n=4 and there are segments [1,4][1,4], [2,3][2,3], [3,6][3,6], [5,7][5,7], then:

  • erasing the first segment will lead to [2,3][2,3], [3,6][3,6], [5,7][5,7] remaining, which have 11 segment in their union;
  • erasing the second segment will lead to [1,4][1,4], [3,6][3,6], [5,7][5,7] remaining, which have 11 segment in their union;
  • erasing the third segment will lead to [1,4][1,4], [2,3][2,3], [5,7][5,7] remaining, which have 22 segments in their union;
  • erasing the fourth segment will lead to [1,4][1,4], [2,3][2,3], [3,6][3,6] remaining, which have 11 segment in their union.

Thus, you are required to erase the third segment to get answer 22.

Write a program that will find the maximum number of segments in the union of n−1n−1 segments if you erase any of the given nn segments.

Note that if there are multiple equal segments in the given set, then you can erase only one of them anyway. So the set after erasing will have exactly n−1n−1 segments.

Input

The first line contains one integer tt (1≤t≤1041≤t≤104) — the number of test cases in the test. Then the descriptions of tt test cases follow.

The first of each test case contains a single integer nn (2≤n≤2⋅1052≤n≤2⋅105) — the number of segments in the given set. Then nn lines follow, each contains a description of a segment — a pair of integers lili, riri (−109≤li≤ri≤109−109≤li≤ri≤109), where lili and riri are the coordinates of the left and right borders of the ii-th segment, respectively.

The segments are given in an arbitrary order.

It is guaranteed that the sum of nn over all test cases does not exceed 2⋅1052⋅105.

Output

Print tt integers — the answers to the tt given test cases in the order of input. The answer is the maximum number of segments in the union of n−1n−1 segments if you erase any of the given nn segments.

链接:http://codeforces.com/problemset/problem/1285/E

题意:很多条[l,r]边,删除其中一条边,计算并区间最大数量。

题解:https://www.luogu.com.cn/problemnew/solution/CF1285E(大佬写的,记笔记学习)

#include <bits/stdc++.h>
using namespace std;
#define R register
#define ll long long
#define sum(a, b, mod) (((a) + (b)) % mod)

const int MaxN = 1e6 + 10;

std::map<int, int> m1, m2;
int n, cnt, l[MaxN], r[MaxN], a[MaxN], s[MaxN];

inline void prework()//离散 
{
    m1.clear(), m2.clear();
    for (int i = 1; i <= n; i++)
        m1[l[i]] = m1[r[i]] = 1;
    cnt = 0;
    for (std::map<int, int>::iterator it = m1.begin(); it != m1.end(); it++)
        m2[it->first] = ++cnt;
    for (int i = 1; i <= n; i++)
    	{
    		l[i] = m2[l[i]] * 2 - 1, r[i] = m2[r[i]] * 2 - 1;
		}
}

inline int read()
{
    int x = 0, f = 1;
    char ch = getchar();
    while (ch > '9' || ch < '0')
    {
        if (ch == '-')
            f = 0;
        ch = getchar();
    }
    while (ch <= '9' && ch >= '0')
        x = (x << 1) + (x << 3) + (ch ^ 48), ch = getchar();
    return f ? x : (-x);
}

int main()
{
    int T = read();
    while (T--)
    {
        n = read(), cnt = 0;
        for (int i = 1; i <= n; i++)
            l[i] = read(), r[i] = read();
        prework(), cnt = cnt * 2 - 1;	//cnt=离散完,l~r点的数量 
        for (int i = 1; i <= n; i++)	//差分 
            a[l[i]]++, a[r[i] + 1]--;
        for (int i = 1; i <= cnt; i++)	//求各点的值 
            a[i] += a[i - 1];
        int num = 0, ans = -1000000;
        for (int i = 1; i <= cnt; i++)  
        {
            s[i] = s[i - 1];	//s[i]为计算a[i]=1的前缀和数量 
            num += (a[i] && !a[i - 1]);	//计算有多少并区间 
            if (a[i] > 1 && a[i - 1] <= 1)
                ++s[i];
        }
        for (int i = 1; i <= n; i++)//枚举边,产生多少区间。 
        {
            int cur = s[r[i]] - s[l[i] - 1] + ((a[l[i]] > 1) && (a[l[i] - 1] > 1)) - 1;
            ans = std::max(ans, cur);
        }
        printf("%d\n", num + ans);
        for (int i = 0; i <= cnt * 2; i++)
            a[i] = s[i] = 0;
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值