您的位置:首页 > 理论基础 > 计算机网络

hihocoder1236(北京网络赛J):scores 分块+bitset

2015-09-23 11:34 537 查看
北京网络赛的题- -。当时没思路,听大神们说是分块+bitset,想了一下发现确实可做,就试了一下,T了好多次终于过了

题意:

初始有n个人,每个人有五种能力值,现在有q个查询,每次查询给五个数代表查询的五种能力值,输出有多少个人每种能力值都比查询的小

n和q都是50000,每种能力值最大也为50000

思路:

对于某一个大小的能力值,有哪些人的此项能力值比他小可以用一个50000的bitset表示。这样我们在查询的时候就可以拿到5个对应的bitset,对其进行and就可以得出最终的人数

这样每组询问的复杂度为5*n/32 总复杂度较高但勉强可以接受。

但是这样做有一点问题就是要开5*50000个大小为50000的bitset,显然这样会超内存。。于是想到将bitset分块,这样虽然询问时需要花费一定时间(sqrt)来找到5个bitset

但是显然这个时间是小于n/32的,所以并不会对总时间造成较大的影响,于是显然可行

注意一点就是分块的时候不仅要按照分数段分块,还要按照人数分块,否则如果某个分数段人数太多就gg了

代码:

#include <bits/stdc++.h>
using namespace std;
bitset<50010>b[7][500];
bitset<50010>tmp;
int n,m,q;
int a[50010][7];
vector<int>v[7][50010];
bitset<50010>p[7];
int tt=10;
int now[5];
vector<int>d[7];
int main()
{
//freopen("in.txt","r",stdin);
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
for(int i=0; i<5; i++)
{
d[i].clear();
for(int j=1; j<=m; j++)
{
v[i][j].clear();
}
}
for(int i=0;i<5;i++)
{
for(int j=1;j<=300;j++)
{
b[i][j].reset();
}
}
for(int i=0; i<n; i++)
{
for(int j=0; j<5; j++)
{
scanf("%d",a[i]+j);
v[j][a[i][j]].push_back(i);
}
}
int tm=0;
for(int i=0; i<5; i++)
{
tm=0;
tmp.reset();
b[i][0]=tmp;
d[i].push_back(0);
for(int j=0; j<=m; j++)
{
for(int to:v[i][j])
{
tmp[to]=1;
tm++;
}
if(tm>sqrt(n)||j-d[i][(int)d[i].size()-1]>sqrt(m)||j==m)
{
b[i][(int)d[i].size()]=tmp;
d[i].push_back(j);
tm=0;
}
}
}
scanf("%d",&q);
int pre=0;
tm=0;
while(q--)
{
for(int i=0; i<5; i++)
{
scanf("%d",now+i);
now[i]^=pre;
}
for(int i=0; i<5; i++)
{
int kk=upper_bound(d[i].begin(),d[i].end(),now[i])-d[i].begin();
kk--;
p[i]=b[i][kk];
for(int j=d[i][kk]+1; j<=now[i]; j++)
{
for(int to:v[i][j])
{
p[i][to]=1;
}
}
//p&=tmp;
}
for(int i=1;i<5;i++)
{
p[0]&=p[i];
}
int ans=p[0].count();
pre=ans;
printf("%d\n",ans);
}
}
return 0;
}


View Code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: