不是很擅长做这类题目 所以直接看了官方题解 觉得非常巧妙 首先是转换为有多少个线段不包含点 然后将点和线段离线处理 每个线段右端点存其左端点位置 每组点的每个点存其前一个点的位置 这样我们需要统计的线段一定位于两个点之间 遇到每个右端点 就在其左端点的位置加一 这样查询两个点之间左端点的数量就可以了
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<vector>
#include<list>
#include<set>
#include<map>
#include<stack>
#include<queue>
#define INF (1ll<<62)
#define pb push_back
using namespace std;
typedef long long ll;
#define bug puts("===========");
const double pi=(acos(-1.0));
const double eps=1e-8;
const int inf=1e9+10;
const int maxn=1e6+5;
const int mod=1e9+7;
/*===============================*/
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1 | 1
int tree[maxn + 10], N;
inline int lowbit(int x) {
return (x & -x);
}
void add(int x, int v) {
if(x==0)puts("1111");
for (int i = x; i <= N; i += lowbit(i))
tree[i] += v;
}
int get(int x) {
int sum = 0;
for (int i = x; i; i -= lowbit(i))
sum += tree[i];
return sum;
}
struct T{
int left,id;
T(const int &left=0,const int &id=0):left(left),id(id) {}
};
vector<T> a[maxn];
int ans[maxn];
int main()
{
int n,m;
N=1e6+1;
while(~scanf("%d%d",&n,&m)){
memset(tree,0,sizeof(tree));
memset(ans,0,sizeof(ans));
for(int i=0;i<maxn;i++)
a[i].clear();
for(int i=0;i<n;i++){
int r,l;
scanf("%d%d",&l,&r);
a[r].pb((T){l,-1});
}
for(int i=0;i<m;i++){
int last=0,mm,now;
scanf("%d",&mm);
for(int j=0;j<mm;j++){
scanf("%d",&now);
a[now].pb((T){last,i+1});
last=now;
}
a[N].pb((T){last,i+1});
}
for(int i=1;i<=N;i++){
int si=a[i].size();
for(int j=si-1;j>=0;j--){
T now=a[i][j];
if(now.id==-1) add(now.left,1);
else {
ans[now.id-1]+=get(i)-get(now.left);
}
}
}
for(int i=0;i<m;i++) printf("%d\n",n-ans[i]);
}
return 0;
}