2015年北京网络赛 J Clarke and puzzle 求五维偏序 分块+bitset

题目

Description
Kyle is a student of Programming Monkey Elementary School. Just as others, he is deeply concerned with his grades.

Last month, the school held an examination including five subjects, without any doubt, Kyle got a perfect score in every single subject.

There are n students took part in this examination(not including Kyle), and everyone got an integer between 1 to m as the score of one subject.

Now, looking at the grade table of these n students, Kyle wants to know how many students still did no better than him even if his scores are something else – Here, “no better” means there is no subject in which the student got strictly greater score than Kyle.

Input
There are multiple test cases.

The first line of the input contains an integer T (T <= 3) which means the number of test cases.

The first line of each test case contains two integers, n, m(n, m≤ 50,000), which are the number of students and the perfect score of each subject.

In the next n lines, each line consists of five integers, indicating a student’s scores.

Then one line follows. This line contains an integer q(q≤ 50,000) indicating the number of queries.

In the next q lines, each line contains five integers as well, representing a query. Each query indicates a set of scores, and for each query, you should figure out that if Kyle's grade is this set of scores, how many students still did no better than him. But for the sake of security, only the first query is in its original form, and other queries are encrypted. To decrypt a query, you must let each integer in the query do xor operation with the answer of last query. It's guaranteed that all the decrypted queries contain integers between 1 and 50000.

Output
For each test case, you should output q lines as the answer for all queries.
Sample Input
2
2 3
1 1 1 1 1
2 2 2 2 2
2
1 1 1 1 1
3 3 3 3 3
3 5
1 1 1 1 1
1 1 1 1 1
1 2 3 4 5
2
1 1 1 1 1
1 1 1 1 1
Sample Output

1
2
2
2
HINT

In case 1, there are two students with different scores and the scores of the first student (1, 1, 1, 1, 1) are not larger than the first query (1 1 1 1 1) in every subject, so the answer for this query is 1.

After having xor operation with the last answer 1, the second query (3,3,3,3,3) will be decrypted into (2, 2, 2, 2, 2). Because both students’ scores are no better than (2, 2, 2, 2, 2), so the answer for query 2 is 2.

题解

因为每次询问都要和上次询问异或,所以这个题目是道强制在线的题目,那么我们应该如何解决呢,首先我们知道这个题目是一个裸的五位偏序的题目,那么二维三维的偏序大家应该都知道,就是用树状数组和cdq分治,那么这道题目的话,强制在线,cdq分治失效,那么我们一个如何去做呢,首先我们肯定考虑暴力,那么大概的做法就是存下每一维的状态,然后询问的时候,取查询每一维前面的一个状态,然后相与,那么就可以得到答案了,但是复杂度爆了,那么我们看看如何优化,分块大法吼啊!!然后的话我们发现,每一个块代表的状态是可以从前面转移过来的,并且要做一系列的位运算,那么我们使用bitset来压位就好了。

代码实现

#include<cstdio>
#include<algorithm>
#include<vector>
#include<queue>
#include<set>
#include<map>
#include<iostream>
#include<cstring>
#include<bitset>
#include<cmath>
using namespace std;
#define rep(i,f_start,f_end) for (int i=f_start;i<=f_end;++i)
#define per(i,n,a) for (int i=n;i>=a;i--)
#define MT(x,i) memset(x,i,sizeof(x) )
#define rev(i,start,end) for (int i=start;i<end;i++)
#define inf 0x3f3f3f3f
#define mp(x,y) make_pair(x,y)
#define lowbit(x) (x&-x)
#define MOD 1000000007
#define exp 1e-8
#define N 1000005 
#define fi first 
#define se second
#define pb push_back
typedef long long ll;
typedef unsigned long long ull;
const ll INF=0x3f3f3f3f3f3f3f3f;
typedef vector <int> VI;
typedef pair<int ,int> PII;
typedef pair<int ,PII> PIII;
ll gcd(ll a,ll b){return b==0?a:gcd(b,a%b);}
ll lcm(ll a,ll b){return a/gcd(a,b)*b;};
void check_max (int &a,int b) { a=max (a,b);}
void check_min (int &a,int b) { a=min (a,b);}
const int maxn=5e4+10;
int n,m;
struct node {
    int x,y;
}a[6][maxn];
bool cmp (node a,node b) {
    return a.x<b.x;
}
int now[7];
bitset <maxn> b[7][270];
bitset <maxn> ans[7];
int l[300],r[300];
int belong[maxn];


void solve () {
    scanf ("%d%d",&n,&m);
    rep (i,1,5) 
     rep (j,1,250) b[i][j].reset ();
    rep (i,1,n) 
     rep (j,1,5)  {
        scanf ("%d",&a[j][i].x);
        a[j][i].y=i;
    } 
    rep (i,1,5) sort (a[i]+1,a[i]+1+n,cmp);
    int block=sqrt (n);
    int num=n/block; if (n%block) num++;
    rep (i,1,num) l[i]=block*(i-1)+1,r[i]=i*block;
    r[num]=n;
    rep (i,1,n) belong[i]=(i-1)/block+1;
    rep (i,1,5) 
     rep (j,1,num) {
        b[i][j]|=b[i][j-1];
        rep (k,l[j],r[j]) b[i][j][a[i][k].y]=1;
    }
    int q;
    scanf ("%d",&q);
    int lastans=0;
    while (q--) {
       rep (i,1,5) scanf ("%d",&now[i]);
       rep (i,1,5) now[i]^=lastans;
       rep (i,1,5) ans[i].reset ();
       rep (i,1,5) {
           int L=0,R=n;
           while (L<=R) {
               int mid= (L+R)>>1;
               if (now[i]>=a[i][mid].x) L=mid+1;
               else R=mid-1;
           }
           int p=L-1;
           if (p==0) continue;
           ans[i]|=b[i][belong[p]-1];
           rep (j,l[belong[p]],p) ans[i][a[i][j].y]=1;
       }
       ans[1]=ans[2]&ans[2]&ans[3]&ans[4]&ans[5];
       lastans=ans[1].count ();
       printf ("%d
",lastans);
    } 

    return ;
}

int main () {
    int t;
    scanf ("%d",&t);
    while (t--) {
        solve ();
    }
    return 0;
}
原文地址:https://www.cnblogs.com/hhlya/p/13869240.html