跳转至

装备合成

题意

给定 k 个装备,每个装备有 n 个属性。

维护 q 组操作:

  • 新建一个装备,其每项属性为 xy 装备对应属性的最小值
  • 新建一个装备,其每项属性为 xy 装备对应属性的最大值
  • 回答 x 装备的 y 属性

解析

这道题和今年冬令营抄了同一道题 Magic Breeding,而且这道题几乎完全照抄。

虽然 a_{i,j} 值域很大,但答案只有可能是 ka_{i,j} 中的一个。枚举 k 个初始装备分别作为基准,设 0 表示小于基准的这一属性,1 表示大于等于基准的这一属性,就可以将每种装备表示为一个 01 串。取最大值就是按位或,最小值就是按位与,这些都可以用 std::bitset 实现,时间复杂度为 O(\frac{nq}{\omega})

当然还有更优秀的复杂度为 O(2^kq) 的做法。枚举当前属性的基准值,用 S 压缩所有装备对应属性相对基准值的大小关系。由于 S 只有 2^k 种取值,维护每个 S 的结果即可。

实现

#include <bits/stdc++.h>

template <typename Tp>
void read(Tp &res){
    static char ch; ch = getchar(), res = 0;
    while(!std::isdigit(ch)) ch = getchar();
    while(std::isdigit(ch)) res = res * 10 + ch - 48, ch = getchar();
}

typedef unsigned long long int ull;
const int maxk = 14, maxn = 1e5 + 19;

struct bitset{
    std::vector<ull> mk;
    void set(int pos, bool val){
        mk[pos >> 6] |= (1ull << (pos & 63));
        if(!val)
            mk[pos >> 6] ^= (1ull << (pos & 63));
    }
    bool access(int pos){
        return mk[pos >> 6] & (1ull << (pos & 63));
    }
    bitset &operator&=(const bitset &b){
        int sz = b.mk.size();
        for(int i = 0; i < sz; ++i)
            mk[i] &= b.mk[i];
        return *this;
    }
    bitset &operator|=(const bitset &b){
        int sz = b.mk.size();
        for(int i = 0; i < sz; ++i)
            mk[i] |= b.mk[i];
        return *this;
    }
};

int n, k, q, a[maxk][maxn];
bool vist[maxn];
int tmp[maxn], tot, id[maxn];
int op[maxn], x[maxn], y[maxn], ans[maxn];
bitset t[maxn];

int main(){
    read(n), read(k), read(q);
    for(int i = 1; i <= k; ++i)
        for(int j = 1; j <= n; ++j)
            read(a[i][j]);
    for(int i = 1; i <= q; ++i){
        read(op[i]), read(x[i]), read(y[i]);
        if(op[i] == 3)
            vist[y[i]] = true;
    }

    for(int i = 1; i <= n; ++i)
        if(vist[i])
            tmp[++tot] = i, id[i] = tot;
    for(int i = 1; i <= k; ++i)
        t[i].mk.resize(tot / 64 + 1);

    for(int i = 1; i <= k; ++i){
        int m = k;
        for(int j = 1; j <= k; ++j){
            for(int p = 1; p <= tot; ++p)
                t[j].set(p, a[j][tmp[p]] >= a[i][tmp[p]]);
        }
        for(int j = 1; j <= q; ++j){
            if(op[j] == 1){
                t[++m] = t[x[j]];
                t[m] |= t[y[j]];
            }
            else if(op[j] == 2){
                t[++m] = t[x[j]];
                t[m] &= t[y[j]];
            }
            else{
                if(t[x[j]].access(id[y[j]]))
                    ans[j] = std::max(ans[j], a[i][y[j]]);
            }
        }
    }

    for(int i = 1; i <= q; ++i)
        if(op[i] == 3)
            std::printf("%d\n", ans[i]);
    return 0;
}

来源

NOI.AC #2017 T2

评论