bitset求解高维偏序

bitset求解高维偏序

今天模拟赛不想打了,于是在赛时最后几个小时看的这个。

  • bitset的基础用法

简单介绍几个成员函数

  1. set()/set(pos) : 将所有位/第\(pos\)位赋值为true,时间复杂度\(O(\frac{n}{w})\)/\(O(1)\)
  2. reset()/reset(pos) : 将所有位/第\(pos\)位赋值为false,时间复杂度\(O(\frac{n}{w})\)/\(O(1)\)
  3. filp()/filp(pos) : 将所有位/第\(pos\)取反,时间复杂度同上
  4. & / | / << / >> 等运算符,时间复杂度\(O(\frac{n}{32})\)
  5. 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)\)的常数?

但是非常难调,然后我没写出来……

posted @ 2024-08-21 21:06  CuFeO4  阅读(10)  评论(0编辑  收藏  举报