[CC-CHANOQ]Chef and odd queries

题目大意:
  给定$n(10^5)$个线段$[l_i,r_i](1\leq l_i,r_i\leq n)$,有$q(q\leq10^5)$组询问,每次给出$m_i(\sum m_i\leq n)$个点$x_{i,j}(1\leq x_{i,j}\leq n)$,问这些线段中有多少个线段覆盖了这些点中的奇数个点。

思路:
  $q$比较小时,只需要对于每个位置$i$,处理位置$1\sim i$的点数前缀和。然后即可$O(1)$判断每个线段覆盖的点数的奇偶性。单笔询问时间复杂度$O(n+m)$。
  由于$\sum m_i$有限制,所以当$q$比较大时,$m_i$就不会很大。可以用主席树记录对于$1\sim i$之间的左端点,每个区间内的右端点有多少。询问时对$x_{i,j}$排序,$O(m^2)$枚举线段覆盖了哪些点,用主席树求出符合条件的线段数即可。时间复杂度$O(m^2\log n)$。
  因此对于每次询问不同的$m_i$,令较大的$m_i$执行$O(n+m)$的算法,令较小的$m_i$执行$O(m^2\log n)$的算法即可。

 1 #include<cstdio>
 2 #include<cctype>
 3 #include<algorithm>
 4 inline int getint() {
 5     register char ch;
 6     while(!isdigit(ch=getchar()));
 7     register int x=ch^'0';
 8     while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
 9     return x;
10 }
11 const int N=1e5+1,M=1e5+2,logN=18;
12 int p[M],cnt[N];
13 std::pair<int,int> seg[N];
14 class FotileTree {
15     private:
16         struct Node {
17             int sum,left,right,vis;
18         };
19         Node node[N*logN];
20         int sz,new_node(const int &p,const int &id) {
21             node[++sz]=node[p];
22             node[sz].vis=id;
23             return sz;
24         }
25     public:
26         int root[N];
27         void modify(int &p,const int &b,const int &e,const int &x,const int &id) {
28             if(node[p].vis!=id) p=new_node(p,id);
29             node[p].sum++;
30             if(b==e) return;
31             const int mid=(b+e)>>1;
32             if(x<=mid) modify(node[p].left,b,mid,x,id);
33             if(x>mid) modify(node[p].right,mid+1,e,x,id);
34         }
35         int query(const int &p,const int &q,const int &b,const int &e,const int &l,const int &r) const {
36             if(b==l&&e==r) return node[q].sum-node[p].sum;
37             const int mid=(b+e)>>1;
38             int ret=0;
39             if(l<=mid) ret+=query(node[p].left,node[q].left,b,mid,l,std::min(mid,r));
40             if(r>mid) ret+=query(node[p].right,node[q].right,mid+1,e,std::max(mid+1,l),r);
41             return ret;
42         }
43         void reset() {
44             sz=0;
45         }
46 };
47 FotileTree t;
48 int main() {
49     for(register int T=getint();T;T--) {
50         t.reset();
51         const int n=getint();
52         for(register int i=1;i<=n;i++) {
53             const int l=getint(),r=getint();
54             seg[i]=std::make_pair(l,r);
55         }
56         std::sort(&seg[1],&seg[n]+1);
57         for(register int i=1,j=1;i<=n;i++) {
58             t.root[i]=t.root[i-1];
59             for(;j<=n&&seg[j].first==i;j++) {
60                 t.modify(t.root[i],1,n,seg[j].second,i);
61             }
62         }
63         for(register int i=getint();i;i--) {
64             const int m=getint();
65             for(register int i=1;i<=m;i++) p[i]=getint();
66             int ans=0;
67             if(m<=50) {
68                 p[m+1]=n+1;
69                 std::sort(&p[1],&p[m]+1);
70                 for(register int i=1;i<=m;i++) {
71                     if(p[i]==p[i-1]) continue;
72                     for(register int j=i;j<=m;j+=2) {
73                         if(p[j]==p[j+1]) continue;
74                         ans+=t.query(t.root[p[i-1]],t.root[p[i]],1,n,p[j],p[j+1]-1);
75                     }
76                 }
77             } else {
78                 for(register int i=1;i<=n;i++) cnt[i]=0;
79                 for(register int i=1;i<=m;i++) cnt[p[i]]++;
80                 for(register int i=1;i<=n;i++) cnt[i]+=cnt[i-1];
81                 for(register int i=1;i<=n;i++) {
82                     ans+=(cnt[seg[i].second]-cnt[seg[i].first-1])&1;
83                 }
84             }
85             printf("%d\n",ans);
86         }
87     }
88     return 0;
89 }

 

posted @ 2018-03-13 14:08  skylee03  阅读(126)  评论(0编辑  收藏  举报