ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Codeforces Round #690 (Div. 3) F. The Treasure of The Segments (二分+主席树)

2020-12-16 12:59:59  阅读:250  来源: 互联网

标签:690 int 线段 Treasure tree mid 端点 root Segments


题目链接

题意:定义good线段集合:该集合中至少存在一条线段(x)与集合内其他所有线段(others)都至少有一个交点。给定n条线段,求最少删除几条线段,使得剩下的线段集合是good。

思路:稍微转化一下题意,就是求good线段集合的大小最大是多少。考虑枚举每一个线段,让其作为线段X,然后求出其他线段中与X有交点的个数。先将线段按照左端点排序。对于当前枚举的线段X,[L,R],在数组下标[X,N]的范围内二分找到最大的左端点小于等于R的位置pos。那么[X+1,pos]区间内的线段都与X至少存在一个 交点,都可以加入到good集合中。目前已经找到了所有左端点与线段X有交点的线段,还少算了那些左端点不与线段X相交,但右端点与线段X相交的线段,这部分也可以加入good集合。然而右端点是无序的,也就不能二分,得另寻他法。左端点不与线段X相交的线段集合就是[1,X-1],在这里面找到右端点与线段X有交点的。这里考虑以线段右端点作为权值,建立主席树(需要先离散化),区间查询权值介于【L,R】之间的个数。二分算出的部分加上主席树查询得到的部分相加就是其他线段中与X有交点的个数。总体时间复杂度 n ∗ l o g n n*log^n n∗logn

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 2e5 + 5;
int a[MAXN];
vector<int> v;
int getid(int x)
{
    return lower_bound(v.begin(), v.end(), x) - v.begin() + 1;
}
struct node
{
    int l, r;
    int sum;
    int ans;
} tree[MAXN * 20];
int root[MAXN];
int cnt = 0;
#define ls(x) tree[x].l
#define rs(x) tree[x].r
void insert(int l, int r, int pre, int &now, int val)
{

    now = ++cnt;
    tree[now] = tree[pre];
    tree[now].sum++;
    if (l == r)
        return;
    int mid = (l + r) >> 1;
    if (val <= mid)
        insert(l, mid, ls(pre), ls(now), val);
    if (val > mid)
        insert(mid + 1, r, rs(pre), rs(now), val);
}
int query(int l, int r, int qL, int qR, int rootL, int rootR)
{
    if (l >= qL && r <= qR)
    {
        return tree[rootR].sum - tree[rootL].sum;
    }
    int mid = (l + r) >> 1;
    int res = 0;
    if (qL <= mid)
        res += query(l, mid, qL, qR, ls(rootL), ls(rootR));
    if (qR > mid)
        res += query(mid + 1, r, qL, qR, rs(rootL), rs(rootR));
    return res;
}
struct Line
{
    int l, r;
} L[MAXN];

int main()
{
#ifdef DEBUG
    freopen("1.in", "r", stdin);
    freopen("1.out", "w", stdout);
#endif
    int t;
    scanf("%d", &t);
    while (t--)
    {
        int n;
        scanf("%d", &n);
        v.clear();
        for (int i = 1; i <= n; i++)
        {
            root[i]=0;
            scanf("%d%d", &L[i].l, &L[i].r);
            v.push_back(L[i].l);
            v.push_back(L[i].r);
        }
        sort(v.begin(), v.end());
        v.erase(unique(v.begin(), v.end()), v.end());
        sort(L + 1, L + 1 + n, [](const Line &fi, const Line &se) {
            return fi.l < se.l;
        });
        for (int i = 1; i <= n; i++)
        {
            insert(1, v.size(), root[i - 1], root[i], getid(L[i].r));
        }
        int res = 0;
        for (int i = 1; i <= n; i++)
        {
            int l = i, r = n;
            while (l <= r)
            {
                int mid = l + r >> 1;
                if (L[mid].l <= L[i].r)
                {
                    l = mid + 1;
                }
                else
                    r = mid - 1;
            }
            int ans = l - i;
            //[1,i-1] [L[i].l,L[i].r]
            ans += query(1, v.size(), getid(L[i].l), getid(L[i].r),root[0],root[i-1]);
            res = max(res, ans);
        }
        printf("%d\n", n - res);
        //memset(root, 0, sizeof(root));
        //memset(tree, 0, sizeof(tree));
        for(int i=0;i<=cnt;i++)tree[i]=tree[0];
        cnt = 0;
    }
    return 0;
}

标签:690,int,线段,Treasure,tree,mid,端点,root,Segments
来源: https://blog.csdn.net/weixin_43645523/article/details/111257349

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有