CodeChef---- February Challenge 2018----Chef and odd queries(复杂度分块计算)
链接 https://www.codechef.com/FEB18/problems/CHANOQ/
Chef and odd queries Problem Code: 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(); } }