Codeforces Round #216_div2_E.Valera and Queries

转载注明出处  http://blog.csdn.net/moedane

 

 

传送门 http://codeforces.com/contest/369/problem/E

 

题意

给出n条线段,以及m个询问,每个询问包括cnt个点,问有多少条线段覆盖了至少一个点。

 

思路

我一开始是正着思考,想着怎样直接统计出覆盖的线段就好了。这样想的话要解决一个重复的问题,即一个线段覆盖了多个点。想直接用前缀和后缀和处理,但是样例都没法过,发现有许多问题。最后去看了别人代码才知道解法。

 

对每个询问,找出一个点都不覆盖的线段的数目。

要找出一个点都不覆盖的线段,方法是,用结构体存储询问的当前点和它左边的点,把落在该区域内的线段数目统计出来即可。对于每个询问,最左端端点可设为0,最右端可设为10^6,即问题转化为求落在这些区间内的线段的数目。

至于求这些线段数目的方法,是限制右端点小于当前询问的右端点,左端点则更新到树状数组中,即可找到当前区间内的线段数目。

先将线段排好序,离线处理询问。

 

代码

 

#include <iostream>
#include <string>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <vector>
#include <queue>
#include <stack>
#include <map>
#include <cctype>
#define bug puts("here");

using namespace std;

typedef long long ll;

const int maxn = 3 * 100086;
const int mod = 1000000007;
const double PI = atan(1.0)*4.0;

int f[1000086];
int Ans[maxn];

struct Node
{
    int l,r,index;
}s[maxn],q[maxn*2];

bool cmp(Node a,Node b)
{
    return a.r < b.r;
}

int lowbit(int x)
{
    return x&(-x);
}

void update(int p,int v)
{
    while(p < 1000006)
    {
        f[p] += v;
        p += lowbit(p);
    }
    return;
}

int sum(int p)
{
    int ans = 0;
    while(p)
    {
        ans += f[p];
        p -= lowbit(p);
    }
    return ans;
}

int main()
{
    int m,n;
    scanf("%d%d",&n,&m);
    int i,j;
    for(i=0;i<n;i++)
        scanf("%d%d",&s[i].l,&s[i].r);
    int e = 0;
    for(i=0;i<m;i++)
    {
        int cnt;
        scanf("%d",&cnt);
        for(j=0;j<cnt;j++)
        {
            scanf("%d",&q[e].r);
            q[e].index = i;
            if(j == 0) q[e].l = 0;
            else q[e].l = q[e-1].r;
            e++;
        }
        q[e].index = i;
        q[e].l = q[e-1].r;
        q[e++].r = 1000006;
    }
    sort(s,s+n,cmp);
    sort(q,q+e,cmp);
    for(i=0;i<m;i++) Ans[i] = n;
    memset(f,0,sizeof(f));
    j = 0;
    for(i=0;i<e;i++)
    {
        while(j < n && s[j].r < q[i].r)
        {
            update(s[j].l,1);
            j++;
        }
        Ans[q[i].index] -= sum(q[i].r - 1) - sum(q[i].l);
    }
    for(i=0;i<m;i++) printf("%d\n",Ans[i]);
    return 0;
}


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值