codeforces 878D

思维题(看了题解后自己又画了半天才搞懂…)

题意:给出 k 12 )个生物,每个生物有 n 105 )个特性,然后 q 105 )个操作,每次操作可以任选之前的两个生物产生一个新生物(特性为这两个生物的特性的max/min值),也可以询问之前某个生物的某个特性。

思路:每次产生的新生物的特性都是基于初始的 k 个生物,因此后续产生的每个生物都可以用前 k 个生物一系列的max/min操作来表示。这里我们给每个生物定义一个新属性( 2k 个比特位),以此来间接表示前 k 个生物的一系列操作后的结果。初始时,对于 1 ~ k 中的第 i 生物而言,将 0 ~ 2k1 这些数字中第 i 个比特为 1 的数字置为 1 ,其余为 0 。那么后续对于这些生物的max/min操作也就转换为了它们这个新属性的或/与运算。例如,操作max(第 i 生物,第 j 生物)得到的就是将 0 ~ 2k1 这些数字中第 i 个比特为 1 或者第 j 个比特为 1 的数字置为 1 ,其余为 0 。(这时对于新生物而言, 0 ~ 2k1 里面被置为1数字变多了);反之。那么询问生物 x 某个特性 y 操作时,我们依次在前 k 个生物从高到低枚举这个特性 y (所对应的前 k 个生物的编号),然后看看当前枚举到的生物的新属性是否被生物 x 的新属性包括在内(也就是看 x 的新属性中的某个比特位是否为 1 )。

#include 
#include 
#include 

using namespace std;
const int maxn = 100050;

int a[15][maxn], rk[maxn][15];
bitset<4096> bt[maxn];

int cmp_id;
bool cmp(const int x, const int y) {
    return a[x][cmp_id] < a[y][cmp_id];
}

int main() {
    int n, k, q;
    while(scanf("%d%d%d",&n,&k,&q) == 3) {
        for(int i=1; i<=k; i++)
            for(int j=1; j<=n; j++) {
                scanf("%d",&a[i][j]);
                rk[j][i] = i;
            }
        for(int j=1; j<=n; j++) {
            cmp_id = j;
            sort(rk[j]+1, rk[j]+k+1, cmp);
        }
        for(int i=1; i<=k; i++)
            for(int j=0; j<(1<if(j&(1<<(i-1))) bt[i][j] = 1;
                else bt[i][j] = 0;
            }
        int tot = k;
        while(q --) {
            int op, x, y;
            scanf("%d%d%d",&op,&x,&y);
            if(op == 1)
                bt[++tot] = bt[x] | bt[y];
            else if(op == 2)
                bt[++tot] = bt[x] & bt[y];
            else {
                int id = k+1, cur = 0;
                while(bt[x][cur] == 0) {
                    id --;
                    cur |= 1<<(rk[y][id]-1);
                }
                printf("%d\n",a[rk[y][id]][y]);
            }
            /*printf("tot:%d\n",tot);
            for(int j=0; j<(1<
        }
    }
    return 0;
}

你可能感兴趣的:(思维)