【I - Navigation Nightmare】

思路:

  • 二维并查集,水平坐标是一维,竖直坐标是另一维,每维都有自己的par & val
  • 注意一条路同时提供水平和竖直两个维度的新关系。
  • 假设询问时间从小到大,不然若每次都重新并查集会TLE

代码:

  • 157ms 1940kB
//157ms		1940kB


#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];//0 is horizon ; 1 is vertical
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;//dimension
	
	if(op == 'N' || op == 'S')
		dim = 1;
	else
		dim = 0;//horizon
	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;
}

猜你喜欢

转载自blog.csdn.net/flash403/article/details/94620625