思路:
- 二维并查集,水平坐标是一维,竖直坐标是另一维,每维都有自己的par & val。
- 注意一条路同时提供水平和竖直两个维度的新关系。
- 假设询问时间从小到大,不然若每次都重新并查集会TLE。
代码:
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
using namespace std;
const int maxn = 4e4 + 5;
int N,M;
int K;
int par[2][maxn];
int val[2][maxn];
int CUR = 1;
struct EDGE{
int l,r,d;
char op;
}edge[maxn];
void ADDEDGE(int i,int l,int r,int d,char op){
edge[i].l = l;
edge[i].r = r;
edge[i].d = d;
edge[i].op = op;
return ;
}
void INIT(){
memset(par , -1 , sizeof(par));
memset(val , 0 , sizeof(val));
return ;
}
int FIND(int dim,int i){
if(par[dim][i] == -1)
return i;
int tp = par[dim][i];
par[dim][i] = FIND(dim,par[dim][i]);
val[dim][i] = val[dim][i] + val[dim][tp];
return par[dim][i];
}
void UNION(int i){
char op = edge[i].op ;
int l = edge[i].l;
int r = edge[i].r;
int d = edge[i].d;
int dim;
if(op == 'N' || op == 'S')
dim = 1;
else
dim = 0;
if(op == 'S' || op == 'W')
d = -d;
int parl = FIND(dim , l);
int parr = FIND(dim , r);
if(parl != parr){
par[dim][parr] = parl;
val[dim][parr] = val[dim][l] + d - val[dim][r];
}
dim = 1 - dim ;
d = 0;
parl = FIND(dim , l);
parr = FIND(dim , r);
if(parl != parr){
par[dim][parr] = parl;
val[dim][parr] = val[dim][l] + d - val[dim][r];
}
return ;
}
int main(){
INIT();
cin>>N>>M;
for(int i=1;i<=M;i++){
int l,r,d;
char op ;
scanf("%d%d%d %c" , &l , &r , &d , &op);
ADDEDGE(i,l,r,d,op);
}
cin>>K;
while(K--){
int ans;
int l,r,t;
scanf("%d%d%d" , &l , &r , &t);
for(int i=CUR;i<=t;i++)
UNION(i);
int parl_h = FIND(0,l);
int parl_v = FIND(1,l);
int parr_h = FIND(0,r);
int parr_v = FIND(1,r);
if(parl_h != parr_h || parl_v != parr_v)
ans = -1;
else
ans = fabs(val[0][l] - val[0][r]) + fabs(val[1][l] - val[1][r]);
printf("%d\n",ans);
CUR = t+1;
}
return 0;
}