有一个四联通的 N × M N\times M N×M 宫格,开始的时候都是联通的,给出在每两个格子之间建墙(断路)的花费,现在要使得每两个宫格之间只有一条路,并且整个建墙的花费尽可能的少。完成后,每次给出两个宫格,求宫格间的距离。
使得每两个宫格之间只有一条路的话,像不像是树的定义,而对于所有边的权值之和 s u m sum sum,减去 n − 1 n-1 n−1 条边权和就是建墙的花费,要是花费尽可能的少,即使得留下的 n − 1 n-1 n−1条边的边权尽可能的大,即最大生成树问题。而最大生成树完成后,只需要求解树上距离就可以了。
(其实就是之前两个板子合了一下)
struct Edge{
int u, v, w;
//Edge(){}
Edge(int _u = 0, int _v = 0, int _w = 0) : u(_u), v(_v), w(_w){}
bool operator < (const Edge& b) const{
return w < b.w;
}
};
priority_queue<Edge> q;
vector<pair<int, int> >G[maxn];
map<pair<int, int>, pair<int, int> >ans;
vector<int> ask[maxn];
int vis[maxn], dis[maxn], fa[maxn], x[maxn], y[maxn];
void init_dsu(){
rep(i, 0, maxn) fa[i] = i;
}
int found(int x){
return x==fa[x]?x:fa[x]=found(fa[x]);
}
void addedge(int u, int v, int w) {
q.push(Edge(u, v, w));
}
void AddEdge(int u, int v, int w){
G[u].push_back(mk(v, w));
G[v].push_back(mk(u, w));
}
void AddAsk(int u, int v){
ask[u].push_back(v);
ask[v].push_back(u);
}
int Kruskal(int n){
int cost = 0, cnt = 1; ///n-1 lines
Edge now;
while(!q.empty() && cnt<n){
now = q.top();
q.pop();
int fax = found(now.u);
int fay = found(now.v);
if(fax != fay){
cost += now.w;
cnt++;
AddEdge(now.u, now.v, 1);
fa[fax] = fay;
}
}
return cost;
}
void Tarjan(int u) { //dis[root] = 0;
fa[u] = u, vis[u] = 1;
rep(i, 0, G[u].size()) {
if(!vis[G[u][i].fi]){
dis[G[u][i].fi] = dis[u] + G[u][i].se;
Tarjan(G[u][i].fi);
fa[G[u][i].fi] = u;
}
}
rep(i, 0, ask[u].size()){
if(vis[ask[u][i]]){
int lca = found(ask[u][i]);
int len = dis[u]+dis[ask[u][i]]-2*dis[lca];
ans[mk(u, ask[u][i])] = ans[mk(ask[u][i], u)] = mk(lca, len);
}
}
}
int main()
{
int n, m, q;
sdd(n, m);
rep(i, 0, n*m){
char op[4];
int w;
scanf("%s%d", op, &w);
if(op[0] == 'D'){
addedge(i, i+m, w);
}
scanf("%s%d", op, &w);
if(op[0] == 'R'){
addedge(i, i+1, w);
}
}
sd(q);
rep(i, 0, q){
int x1, y1, x2, y2;
sdd(x1, y1);
sdd(x2, y2);
x[i] = (x1-1)*m + y1-1;
y[i] = (x2-1)*m + y2-1;
AddAsk(x[i], y[i]);
}
init_dsu();
Kruskal(n*m);
init_dsu();
Tarjan(0);
rep(i, 0, q){
printf("%d\n", ans[mk(x[i], y[i])].se);
}
return 0;
}