bitset求解高维偏序
bitset求解高维偏序
今天模拟赛不想打了,于是在赛时最后几个小时看的这个。
- bitset的基础用法
简单介绍几个成员函数
- set()/set(pos) : 将所有位/第\(pos\)位赋值为true,时间复杂度\(O(\frac{n}{w})\)/\(O(1)\)
- reset()/reset(pos) : 将所有位/第\(pos\)位赋值为false,时间复杂度\(O(\frac{n}{w})\)/\(O(1)\)
- filp()/filp(pos) : 将所有位/第\(pos\)取反,时间复杂度同上
- & / | / << / >> 等运算符,时间复杂度\(O(\frac{n}{32})\)
- count() : 统计为1的个数,复杂度\(O(1的个数)\)
求解高维偏序的话就用这几个(没有全用上),其它的函数可以看另一篇博客虽然还没有写但马上就会补
其实求解高维偏序就是求\(\left|\bigcup\limits_{j=1}^k \{x|a_{j,x}\le a_{i,x}\}\right|\),这个直接用bitset求并集即可。
开\(n\)个 bitset,\(b_{i,j}=1\)表示\(j\)每一维的数值都不超过\(i\)。初始化所有\(b_{i,j}=1\)。
枚举维度,将所有数按照维度排序
开一个新的 bitset \(s\),按这一维从小到大处理所有数,处理到\(i\)时 \(s_j=1\)表示当前维\(j\)不超过 \(i\)。
因为\(j\)是单调的,用一个指针维护即可。
最后\(b_i\)与\(s\)取并集即可
发现开\(n\)个\(n\)维bitset空间会寄,于是考虑分块处理,复杂度不变
预处理的话复杂度确实不变,但是因为难写所以这篇代码是\(O(\frac{n^3k}{bw})\),但是因为\(b\)开的很大加上常数小所以一样可过
点此查看代码
#include<bits/stdc++.h>
#include<bits/extc++.h>
// using namespace __gnu_pbds;
// using namespace __gnu_cxx;
using namespace std;
#define infile(x) freopen(x,"r",stdin)
#define outfile(x) freopen(x,"w",stdout)
#define errfile(x) freopen(x,"w",stderr)
#ifdef LOCAL
FILE *InFile = infile("in.in"),*OutFile = outfile("out.out");
// FILE *ErrFile=errfile("err.err");
#else
FILE *Infile = stdin,*OutFile = stdout;
//FILE *ErrFile = stderr;
#endif
using ll=long long;using ull=unsigned long long;
using db = double;using ldb = long double;
const int N = 1e5 + 10;
int n,emm,ans[N],a[4][N],p[4][N];
bitset<N> vis[9999];
inline void solve(){
cin>>n>>emm;
for(int i = 1;i <= n; ++i)
cin>>a[1][i]>>a[2][i]>>a[3][i],p[1][i] = p[2][i] = p[3][i] = i;
for(int i = 1;i <= 3; ++i){
sort(p[i] + 1,p[i] + 1 + n,[=](int x,int y){return a[i][x] < a[i][y];});
}
for(int l = 1,r;l <= n; l = r + 1){
r = min(l + 9990,n);
for(int i = l;i <= r; ++i) vis[i-l].set();
for(int i = 1;i <= 3; ++i){
bitset<N> s;s.reset();
for(int j = 1,k = 1;j <= n; ++j){
int now = p[i][j];
for(;k <= n && a[i][p[i][k]] <= a[i][now];) s[p[i][k++]] = true;
if(l <= now && now <= r) vis[now - l] &= s;
}
}
for(int i = l;i <= r; ++i) ++ans[vis[i-l].count()];
}
for(int i = 1;i <= n; ++i) cout<<ans[i]<<'\n';
}
signed main(){
cin.tie(nullptr)->sync_with_stdio(false);
cout.tie(nullptr)->sync_with_stdio(false);
solve();
}
啥,你说要多维?改个数就好了呀!
upd : 其实预处理也不难写,就是分块写法,\(b_{i,j}\)表示前\(i\)块j维的状态,时间复杂度没变,但貌似加了一个\(O(b)\)的常数?
但是非常难调,然后我没写出来……
__________________________________________________________________________________________
本文来自博客园,作者:CuFeO4,转载请注明原文链接:https://www.cnblogs.com/hzoi-Cu/p/18372558