Codeforces Round #443 (Div. 1) D. Magic Breeding 状态压缩,bitset优化

来源:互联网 发布:软件所应明生怎样 编辑:程序博客网 时间:2024/06/17 19:25

D. Magic Breeding
time limit per test4 seconds
memory limit per test1024 megabytes
inputstandard input
outputstandard output
Nikita and Sasha play a computer game where you have to breed some magical creatures. Initially, they have k creatures numbered from 1 to k. Creatures have n different characteristics.

Sasha has a spell that allows to create a new creature from two given creatures. Each of its characteristics will be equal to the maximum of the corresponding characteristics of used creatures. Nikita has a similar spell, but in his spell, each characteristic of the new creature is equal to the minimum of the corresponding characteristics of used creatures. A new creature gets the smallest unused number.

They use their spells and are interested in some characteristics of their new creatures. Help them find out these characteristics.

Input
The first line contains integers n, k and q (1 ≤ n ≤ 105, 1 ≤ k ≤ 12, 1 ≤ q ≤ 105) — number of characteristics, creatures and queries.

Next k lines describe original creatures. The line i contains n numbers ai1, ai2, …, ain (1 ≤ aij ≤ 109) — characteristics of the i-th creature.

Each of the next q lines contains a query. The i-th of these lines contains numbers ti, xi and yi (1 ≤ ti ≤ 3). They denote a query:

ti = 1 means that Sasha used his spell to the creatures xi and yi.
ti = 2 means that Nikita used his spell to the creatures xi and yi.
ti = 3 means that they want to know the yi-th characteristic of the xi-th creature. In this case 1 ≤ yi ≤ n.
It’s guaranteed that all creatures’ numbers are valid, that means that they are created before any of the queries involving them.

Output
For each query with ti = 3 output the corresponding characteristic.

Examples
input
2 2 4
1 2
2 1
1 1 2
2 1 2
3 3 1
3 4 2
output
2
1
input
5 3 8
1 2 3 4 5
5 1 2 3 4
4 5 1 2 3
1 1 2
1 2 3
2 4 5
3 6 1
3 6 2
3 6 3
3 6 4
3 6 5
output
5
2
2
3
4
题意:给出k个生物,第一种操作:创造一种新的生物所有的属性是第x个生物和第y个生物对应的属性的较大值,第二种操作,创造一种生物,他的属性值是x生物和y生物对应属性的较小值。第三种操作:询问第x个生物第y个属性的值。
做法:有这样一个思想,对于给出的k个生物的某一种属性,给定一个值a,设属性比这个值大的生物的属性为1,否则为0,那么对于两个生物,如果他们都是1,那么说明他们的属性都属于较大的那个范围,如果有一个为0,一个为1,那么说明有一个生物的属性在较大范围,一个在较小范围,如果两个都是0,那么说明他们都在较小的范围,所以,如果是第一种操作,那么只要有一个为1,新生物也为1,否则为0,这就是或操作,如果是第二种操作,只要有一个为0,那么新生物就是0,这个就是与操作,所以可以从大到小枚举每一位,把大于等于这一位的值设为1,其他设为0,然后去创造新生物,当某个生物第一次为1的时候,说明他的这个属性就是枚举到这一位的值。
这样的复杂度肯定是爆炸的,不过可以法相按照上面的枚举,这k种生物最多只有2^k种,如果我状态压缩暴力吧每一种跑出来,然后对于每一个第三种操作,从最高位的开始枚举,当第一使得这个生物为1的时候,这个生物的这个属性就是这个,可以反向只有0,1的或和,所以可以用bitset优化,复杂度就是q*k/32+q*k*logk

#include<bits/stdc++.h>using namespace std;const int N = 1e5+15;bitset<4096> S[N];int n,k,q;int num[15][N];int main(){    scanf("%d %d %d",&n,&k,&q);    for(int i = 1;i <= k; i++){        for(int j = 1;j <= n;j ++){            scanf("%d",&num[i][j]);        }    }    for(int i = 1;i < 4096;i ++){        for(int j = 1;j <= k;j ++){            if(i&(1<<j-1)) S[j].set(i);        }    }    int tot = k+1;    for(int i = 1;i <= q;i ++){        int op,x,y;        scanf("%d %d %d",&op,&x,&y);        if(op == 1) S[tot++] = S[x]|S[y];        else if(op == 2) S[tot++] = S[x]&S[y];        else{            vector<pair<int,int> > v;            for(int i = 1;i <= k;i ++){                v.push_back({num[i][y],i-1});            }            sort(v.begin(),v.end(),greater<pair<int,int> >());            int b = 0;            for(int i = 0;i < k;i ++){                b |= 1<<(v[i].second);                if(S[x][b]){                    printf("%d\n",num[v[i].second+1][y]);                    break;                }            }        }    }    return 0;}
阅读全文
0 0