codeforces 369E Valera and Queries(树状数组+ 反向思考) 好题

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

题意: 现在给你一些线段,然后每次询问给你cc 个点,然后问你包含这cc个点的一共有多少不相同的线段。反过来思考,如果我把每次询问的点之间的线段抽出来,那么问题就可以转化成,我抽出来的这些线段完全包含了n个线段中的多少个线段。因为完全包含的这些线段对于我该次的询问不会有贡献。那么我把所有的询问离线下来。然后sort 一下线段,然后树状数组维护一下就可以了。

代码:

#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
const int N = 1e6+5;

struct node
{
    int l,r;
    int id;
}xd[N];
int n,m;
int tot;
int c[N];
int ans[300005];

bool cmp(node a,node b)
{
    if(a.l==b.l)
    {
        if(a.r==b.r) return a.id<b.id;
        return a.r<b.r;
    }
    return a.l>b.l;
}

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

void update(int x)
{
    for(;x<N;x+=lowbit(x))
    {
        c[x]++;
    }
}

int query(int x)
{
    int sum=0;
    for(;x>0;x-=lowbit(x))
    {
        sum+=c[x];
    }
    return sum;
}

int main()
{
    scanf("%d %d",&n,&m);
    for(int i=1;i<=n;i++){
        scanf("%d %d",&xd[i].l,&xd[i].r);
    }
    int x;
    tot=n;
    int cc;
    for(int id=1;id<=m;id++){
        scanf("%d",&cc);
        int pre=1;
        scanf("%d",&x);
        if(x==1){
            pre=2;
        }
        else{
            xd[++tot].l=1; xd[tot].r=x-1; xd[tot].id=id;
            pre=x+1;
        }
        for(int i=2;i<=cc;i++){
            scanf("%d",&x);
            if(x>pre){
                xd[++tot].l=pre; xd[tot].r=x-1; xd[tot].id=id;
            }
            pre=x+1;
        }
        xd[++tot].l=pre; xd[tot].r=N-2; xd[tot].id=id;
    }
    /*
    printf("****\n");
    for(int i=1;i<=tot;i++){
        printf("%d %d %d\n",xd[i].l,xd[i].r,xd[i].id);
    }
    printf("****\n");
    */
    sort(xd+1,xd+tot+1,cmp);

    for(int i=1;i<=tot;i++){
        int id=xd[i].id;
        if(id){
            ans[id]+=query(xd[i].r);
        }
        else update(xd[i].r);
    }

    for(int i=1;i<=m;i++){
        printf("%d\n",n-ans[i]);
    }

    return 0;
}

猜你喜欢

转载自blog.csdn.net/yjt9299/article/details/82934892
今日推荐