CodeForces - 369E Valera and Queries(树状数组)


CodeForces - 369E Valera and Queries
题目大意:给出n个线段(线段的左端点和右端点坐标)和m个查询,每个查询有cnt个点,要求给出有多少条线段包含至少其中一个点。
思路:如果按照题意正面去算有每个线段是否包含点,那么时间复杂度是不允许的;如果去算每个点被哪些线段包含,那么去重比较困难。正难则反,因此对于每个查询,选择去求有多少个线段没有覆盖任何一个点,那么答案则为n减所求。用树状数组来统计没有覆盖任何一个点的线段数,大致做法是将临界线段(如x1+1,x2-1)插入seg数组中,再按一定规则进行排序,之后通过树状数组维护统计被包含于临界线段的线段数,具体实现在代码中。
代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=1000000+5;
struct segment
{
    int l,r,id;
};
bool cmp(const segment& a,const segment& b)
{
    if (a.l!=b.l)
        return a.l>b.l;
    if (a.r!=b.r)
        return a.r<b.r;
    return a.id<b.id;
}
segment seg[maxn];
int tree[maxn+5];
void add(int i,int x)
{
    while (i<=maxn)
    {
        tree[i]+=x;
        i+=i&-i;
    }
    return;
}
int sum(int i)
{
    int sum=0;
    while (i>0)
    {
        sum+=tree[i];
        i-=i&-i;
    }
    return sum;
}
int ans[maxn];

int main()
{
    int n,m,i,j;
    cin>>n>>m;
    for (i=0;i<n;++i)
    {
        scanf("%d%d",&seg[i].l,&seg[i].r);
        seg[i].id=0;
    }
    int cnt,x,pre,tt=n;
    for (i=1;i<=m;++i)
    {
        ans[i]=n;
        pre=0;
        scanf("%d",&cnt);
        for (j=0;j<cnt;++j)
        {
            scanf("%d",&x);
            if (pre+1<=x-1)
            {
                seg[tt].l=pre+1;
                seg[tt].r=x-1;
                seg[tt++].id=i;
            }
            pre=x;
        }
        seg[tt].l=pre+1;
        seg[tt].r=maxn;
        seg[tt++].id=i;
    }
    sort(seg,seg+tt,cmp);
    for (i=0;i<tt;++i)
    {
        if (seg[i].id)
        {
            ans[seg[i].id]-=sum(seg[i].r);      
        }
        else
        {
            add(seg[i].r,1);
        }
    }
    for (i=1;i<=m;++i)
    {
        printf("%d\n",ans[i]);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/orangee/p/9011050.html
今日推荐