链接: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;
}