CodeChef---- February Challenge 2018----Chef and odd queries(复杂度分块计算)

链接    https://www.codechef.com/FEB18/problems/CHANOQ/

Let's say that a segment [l, r] crosses a point x if l ≤ x ≤ r.

Chef wants you to answer Q queries. In each query, you are given a set of M distinct points X1, X2, ..., XM; you should compute the number of good segments [Li, Ri] among the given N segments. A segment is good if it crosses an odd number of points out of the given M points.

Input

  • The first line of the input contains a single integer T denoting the number of test cases. The description of T test cases follows.
  • The first line of each test case contains a single integer N denoting the number of segments.
  • The following N lines describe the segments. For each i, the i-th of these lines contains two space-separated integers Li and Ri.
  • The next line contains a single integer Q denoting the number of queries.
  • The following Q lines describe the queries. Each of these lines starts with an integer M — the number of points in this query, followed by M space-separated integers X1, X2, ..., XM.

Constraints

  • 1 ≤ T ≤ 100
  • 1 ≤ Q ≤ N ≤ 100,000
  • sum of M for all queries ≤ N
  • sum of N over all test cases ≤ 200,000
  • 1 ≤ Xi ≤ N for each valid i
  • all Xi in each query are distinct
  • 1 ≤ Li ≤ Ri ≤ N for each valid i

Subtasks

Subtask #1 (10 points): N, Q ≤ 300

Subtask #2 (90 points): original constraints

Output

For each query, print a single line containing the number of good segments for that query.

Example

Input:

2
5
4 5
3 5
2 4
1 3
5 5
2
4 1 2 3 4
1 4
5
4 5
3 5
2 4
2 3
5 5
2
2 2 5
3 1 2 5

Output:

3
3
5
5
/////////////////////////////////////////////////
根据M的大小把询问区分开,M足够大的直接一个o(n)处理,M小的把询问离线了处理
离线后复杂度为d/x*x²logn(d为总点数,x为M小的询问的M值,logn来自树状数组)
贴个自己代码
#include <bits/stdc++.h>
#define mst(a,b)    memset((a),(b), sizeof a)
#define lowbit(a)   ((a)&(-a))
#define IOS         ios::sync_with_stdio(0);cin.tie(0);
using namespace std;
typedef long long ll;
const int mod=1e9+7;
const int maxn=1e5+10;
int n;
int bit[maxn];
void update(int pos){
    while(pos<=n){
        ++bit[pos];
        pos+=lowbit(pos);
    }
}
int get(int pos){
    int ret=0;
    while(pos){
        ret+=bit[pos];
        pos-=lowbit(pos);
    }
    return ret;
}
vector<int>rr[maxn],uu[maxn];
int l[maxn],r[maxn];
int ss[maxn];
int blo;
bool vis[maxn];int ap[maxn];
int x[maxn],sum[maxn];
ll ans[maxn];
struct node{
    int l,to,c;
    node(int a,int b,int d){l=a;to=b;c=d;}
};
vector<node>kk[maxn];
int main(){
#ifdef local
freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
#endif
    int t;scanf("%d",&t);
    while(t--){
        scanf("%d",&n);
        blo=sqrt(n);
        for(int i=1;i<=n;++i)scanf("%d%d",&l[i],&r[i]);

        for(int i=1;i<=n;++i)rr[i].clear(),uu[i].clear(),kk[i].clear(),ss[i]=0;

        for(int i=1;i<=n;++i)rr[r[i]].push_back(l[i]),++ss[l[i]],--ss[r[i]+1];

        for(int i=1;i<=n;++i)ss[i]=ss[i-1]+ss[i];

        int q;scanf("%d",&q);
        for(int id=1;id<=q;++id){
            int m;scanf("%d",&m);
            for(int i=1;i<=m;++i)scanf("%d",&x[i]);
            if(m>=blo-10){
                for(int i=1;i<=m;++i)vis[x[i]]=true;
                for(int i=1;i<=n;++i)sum[i]=sum[i-1]+vis[i];
                int tmp=0;
                for(int i=1;i<=n;++i){
                    int g=sum[r[i]]-sum[l[i]-1];
                    tmp+=(g%2?1:0);
                }
                for(int i=1;i<=m;++i)vis[x[i]]=false;
                ans[id]=tmp;
            }else{
                sort(x+1,x+1+m);
                int tmp=0;
                for(int i=1;i<=m;++i)tmp+=ss[x[i]];
                ans[id]=tmp;
                int cc=-2;
                for(int len=1;len<m;++len){
                    for(int st=1;st+len<=m;++st){
                        int le=x[st],ri=x[st+len];
                        kk[ri].push_back(node(le,id,cc));
                    }
                    cc=-cc;
                }
            }
        }
        for(int i=1;i<=n;++i)bit[i]=0;
        for(int i=n;i>0;--i){
            for(int j=0;j<rr[i].size();++j)update(rr[i][j]);
            for(int j=0;j<kk[i].size();++j){
                node&ha=kk[i][j];
                ans[ha.to]+=ha.c*get(ha.l);
            }
        }
        for(int i=1;i<=q;++i)printf("%lld\n",ans[i]);
    }
    return 0;
}

系数的设置来自一个表格

被计算次数

系数

在计算中被包含的长度

 

1

2

3

4

5

6

计算的长度

1

1

1

2

3

4

5

6

2

-2

 

1

2

3

4

5

3

2

 

 

1

2

3

4

4

-2

 

 

 

1

2

3

5

2

 

 

 

 

1

2

简单来说就是你算覆盖长度为1的实际上把覆盖长度更多的也算进去了,乘上系数后就只剩下奇数的长度了

区分点设置的也不是很好,可能数据不是很变态,0.几秒过了

放个zk的代码,zk  orz,他的代码更容易理解一点(他说也可以用主席树在线查询,emm有道理)

#include <iostream>
#include <fstream>
#include <algorithm>
#include <cstdio>
#include <vector>
#include <map>
#include <cmath>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <stack>
#include <set>
#include <queue>
#include <assert.h>
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
const int N = 1e5 + 7;
const int M = 3e5 + 5;
const LL mod = 1e9 + 7;
#define X first
#define Y second
#define pb push_back
#define mp  make_pair
#define SZ(X) (X.size())
vector<int>F[N];
vector<pii>L;
int ans[N];
int cover[N];
int n,q;
int solve(int x){
    for(int i = 0; i < F[x].size(); i++){
        cover[F[x][i]]++;
    }
    for(int i = 1; i <= n; i++){
        cover[i] += cover[i - 1];
    }
    int ret = 0;
    for(int i = 0; i < L.size(); i++){
        if((cover[L[i].Y] - cover[L[i].X - 1]) & 1)ret++;
    }
    for(int i = 0; i <= n; i++)cover[i] = 0;
    return ret;
}
struct Query{
    int el,er;
    int flag;
    int id;
    Query(){}
    Query(int _el,int _er,int _flag,int _id){
        el = _el;er = _er;flag = _flag;id = _id;
    }
};
vector<Query>Q[N];
int tree[N];
void update(int o){
    while(o <= n){
        tree[o]++;
        o += o & -o;
    }
}
int sum(int l,int r){
    l--;
    int ret = 0;
    while(r){
        ret += tree[r];
        r -= r & -r;
    }
    while(l){
        ret -= tree[l];
        l -= l & -l;
    }
    return ret;
}
void solveQ(){
    int l = 0;
    for(int ql = 0; ql <= n; ql++){
        while(l < n && L[l].X <= ql){
            update(L[l].Y);
            l++;
        }
        for(int j = 0; j < Q[ql].size(); j++){
          ans[Q[ql][j].id] += Q[ql][j].flag * sum(Q[ql][j].el,Q[ql][j].er);
        }
    }
    for(int i = 0; i <= n; i++)tree[i] = 0;
}
int main() {
#ifdef local
    freopen("input", "r", stdin);
#endif // local
    ios::sync_with_stdio(0);
    cin.tie(0);
    int t;
    cin>>t;
    while(t--){
        cin>>n;
        for(int i = 0,l,r; i < n; i++){
            cin>>l>>r;
            L.pb(mp(l,r));
        }
        sort(L.begin(),L.end());
        cin>>q;
        for(int i = 0,xn,x; i < q; i++){
            cin>>xn;
            while(xn--){
                cin>>x;
                F[i].pb(x);
            }
        }
        int split = sqrt((n + 2)/log2(n + 2));
        for(int i = 0; i < q; i++){
            if(F[i].size() > split){
                ans[i] = solve(i);
            }
            else {
                ans[i] = 0;
                sort(F[i].begin(),F[i].end());
                for(int z = 0; z < F[i].size(); z++){
                    for(int j = z; j < F[i].size(); j++){
                        if((j - z) & 1)continue;
                        int el = F[i][j];
                        int er = (j + 1 == F[i].size() ? n : F[i][j + 1] - 1);
                        int x1 = (z == 0 ? 0 : F[i][z - 1]);
                        int x2 = F[i][z];
//                        cout<<x1 + 1<<" "<<x2<<" "<<el<<" "<<er<<endl;
                        Q[x1].pb(Query(el,er,-1,i));
                        Q[x2].pb(Query(el,er,1,i));
                    }
                }
            }
        }
        solveQ();
        for(int i = 0; i < q; i++){
            cout<<ans[i]<<"\n";
        }
        cout<<flush;
        L.clear();
           for(int i = 0; i <= n; i++)Q[i].clear();
        for(int i = 0; i < q; i++)F[i].clear();
    }
}

 

posted on 2018-02-12 17:31  scau_bi  阅读(270)  评论(0编辑  收藏  举报

导航