题意:一棵树,每个树的结点是2*2的01矩阵。
对每个结点有两种操作:
1、将结点上的矩阵进行顺时针旋转,每次旋转花时为2秒;
2、将结点上的矩阵替换成另一个矩阵,每次替换花时为10秒;
然后每个询问都是一对a,b,和一个2*2的01矩阵,这个是目标矩阵。
询问树上结点a到结点b的路径上,将经过的所有结点上的矩阵修改为目标矩阵,并且求出修改的最小花费。
昨晚BC比赛的题目,比赛的时候没注意到题目是询问完会修改的,很开心地跑去写lca,写完调不出样例才花现真相,然而没时间了。。。
解法还是很简单的,通过树链剖分+线段树处理。
由于矩阵有16种,所以线段树结点维护的是这个区间里16个状态的数量。
对于修改操作,如果可以通过旋转得到的,肯定通过旋转,否则才使用替换。
询问的时候,对于一个区间,我们可以从目标矩阵逆时针旋转,得到旋转的状态及花费,区间长度减去这些旋转的,剩下的就都是替换。
旋转可以先预处理,预处理也是逆时针的,因为我们是通过目标矩阵反过来找原矩阵的。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int N = 2e4 + 10;
const int M = 16;
#define pb push_back
inline int encode(int *a){
int ret = 0;
for(int i=0; i<4; i++){
ret = (ret<<1) | a[i];
}
return ret;
}
vector<int> G[M], V[N], MP[N];
void init_g(){//预处理矩阵的逆时针旋转
int a[4], b[4];
int y = 0, z = 0;
for(int i=0; i<M; i++){
y = 0;
for(int j=0; j<4; j++){
a[3-j] = (i&(1<<j))?1:0;
y += a[3-j];
}
G[i].pb(i);
if(y==0 || y==4){
continue;
} else if(y==1 || y==3){
z = 4;
} else {
if(a[0]==a[3]){
z = 2;
} else {
z = 4;
}
}
for(int j=1; j<z; j++){
b[0] = a[1];
b[2] = a[0];
b[3] = a[2];
b[1] = a[3];
for(int k=0; k<4; k++) a[k] = b[k];
G[i].pb(encode(a));
}
}
}
struct TreeNode{
int l, r, s[M], lazy, lch, rch;
}tr[N*10];
#define lson tr[o].lch
#define rson tr[o].rch
#define lchd tr[tr[o].lch]
#define rchd tr[tr[o].rch]
#define cur tr[o]
int T, n, q, val[N];
int path_cnt, node_cnt;
int fa[N], sz[N], belong[N], Rank[N];
int path_dep[N], path_top[N], path_size[N], tree[N];
void maintain(int o){
for(int i=0; i<M; i++){
cur.s[i] = lchd.s[i] + rchd.s[i];
}
}
void build(int path_id, int o, int ll, int rr){
cur.l = ll;
cur.r = rr;
cur.lazy = -1;
if(ll<rr){
int mid = ll+rr>>1;
lson = ++node_cnt;
build(path_id, lson, ll, mid);
rson = ++node_cnt;
build(path_id, rson, mid+1, rr);
maintain(o);
} else {
for(int i=0; i<M; i++) cur.s[i] = 0;
cur.s[MP[path_id][ll-1]] = 1;
}
}
void dfs(int x, int dep){
sz[x] = 1;
int key = -1;
int M = 0;
for(int i=0; i<V[x].size(); i++){
int j = V[x][i];
if(j == fa[x]) continue;
fa[j] = x;
dfs(j, dep+1);
sz[x] += sz[j];
if(sz[j] > M){
M = sz[j];
key = i;
}
}
belong[x] = 0;
for(int i=0; i<V[x].size(); i++){
int j = V[x][i];
if(j == fa[x]) continue;
if(i == key){
belong[x] = belong[j];
Rank[x] = Rank[j]+1;
} else {
int u = belong[j];
path_size[u] = Rank[j];
path_dep[u] = dep;
path_top[u] = j;
}
}
if(!belong[x]){
belong[x] = ++path_cnt;
Rank[x] = 1;
MP[path_cnt].clear();
}
MP[belong[x]].pb(val[x]);
}
void init(){
fa[1] = 0;
path_cnt = node_cnt = 0;
dfs(1, 1);
int u = belong[1];
path_dep[u] = 0;
path_size[u] = Rank[1];
path_top[u] = 1;
for(int i=1; i<=path_cnt; i++){
tree[i] = ++node_cnt;
build(i, tree[i], 1, path_size[i]);
}
}
int query(int o, int ll, int rr, int v);
void pushdown(int o){
if(cur.lazy != -1){
int mid = cur.l + cur.r >> 1;
query(lson, cur.l, mid, cur.lazy);
query(rson, mid+1, cur.r, cur.lazy);
cur.lazy = -1;
}
}
int query(int o, int ll, int rr, int v){
int ret, len;
if(cur.l==ll && cur.r==rr){
len = cur.r - cur.l + 1;
ret = 0;
for(int i=0; i<G[v].size(); i++){
ret += cur.s[G[v][i]] * i * 2;
len -= cur.s[G[v][i]];
}
ret += len * 10;
for(int i=0; i<M; i++){
cur.s[i] = 0;
}
cur.s[v] = cur.r-cur.l + 1;
cur.lazy = v;
return ret;
}
pushdown(o);
int mid = cur.l + cur.r >> 1;
if(rr<=mid) ret = query(lson, ll, rr, v);
else if(ll>mid) ret = query(rson, ll, rr, v);
else{
ret = query(lson, ll, mid, v) + query(rson, mid+1, rr, v);
}
maintain(o);
return ret;
}
int Q(int a, int b, int v){
int x = belong[a];
int y = belong[b];
int ret = 0;
while(x != y){
if(path_dep[x] > path_dep[y]){
ret += query(tree[x], Rank[a], path_size[x], v);
a = fa[path_top[x]];
x = belong[a];
} else {
ret += query(tree[y], Rank[b], path_size[y], v);
b = fa[path_top[y]];
y = belong[b];
}
}
if(Rank[a] > Rank[b]){
ret += query(tree[x], Rank[b], Rank[a], v);
} else {
ret += query(tree[y], Rank[a], Rank[b], v);
}
return ret;
}
int main(){
int x, y, a[4];
init_g();
scanf("%d", &T);
while(T--){
scanf("%d", &n);
for(int i=1; i<=n; i++){
V[i].clear();
}
for(int i=1; i<n; i++){
scanf("%d %d", &x, &y);
V[x].pb(y);
V[y].pb(x);
}
for(int i=1; i<=n; i++){
for(int j=0; j<4; j++) scanf("%d", a+j);
val[i] = encode(a);
}
init();
scanf("%d", &q);
while(q--){
scanf("%d %d", &x, &y);
for(int i=0; i<4; i++) scanf("%d", a+i);
printf("%d\n", Q(x, y, encode(a)));
}
}
return 0;
}