hdu 2874 Connections between cities (lca在线询问)

2 篇文章 0 订阅

题目链接

思路:
第一次做多颗树合用一个lca,记录一下,其实就是一开始init,在加边的时候做一下并查集,把一棵树上的点都算到一个集合去,然后遍历1到n,如果fa[i] == i的话就搞一下lca,这里多颗树是共用一个欧拉序的,但不影响此模板的正确性,因为记录的第一次数显示的位置的都是正确的。
初始化 -> lca+st表 -> 在线询问。

数据有点水把,最极限情况1e10应该要开long long的,int也能过,就这样。

#include <bits/stdc++.h>

#define eb emplace_back
#define mp make_pair
#define mt make_tuple
#define fi first
#define se second
#define pb push_back
#define all(x) (x).begin(), (x).end()
#define rall(x) (x).rbegin(), (x).rend()
#define forn(i, n) for (int i = 0; i < (int)(n); ++i)
#define for1(i, n) for (int i = 1; i <= (int)(n); ++i)
#define ford(i, a, b) for (int i = (int)(a); i >= (int)b; --i)
#define fore(i, a, b) for (int i = (int)(a); i <= (int)(b); ++i)
#define rep(i, l, r) for (int i = (l); i <= (r); i++)
#define per(i, r, l) for (int i = (r); i >= (l); i--)
#define ms(x, y) memset(x, y, sizeof(x))
#define SZ(x) ((int)(x).size())

using namespace std;

typedef pair<int, int> pii;
typedef vector<int> vi;
typedef vector<pii> vpi;
typedef vector<vi> vvi;
typedef long long i64;
typedef vector<i64> vi64;
typedef vector<vi64> vvi64;
typedef pair<i64, i64> pi64;
typedef double ld;

template<class T> bool uin(T &a, T b) { return a > b ? (a = b, true) : false; }
template<class T> bool uax(T &a, T b) { return a < b ? (a = b, true) : false; }

const int maxn = 2*(int)10000+100; //要开两倍点数量的大小(欧拉序长度)
int n, q, m, fa[maxn];
struct LCA
{
	#define type long long
	struct node{int to;type w;node(){}node(int _to,type _w):to(_to),w(_w){}};
	type dist[maxn];
	int path[maxn],dep[maxn],loc[maxn],len[maxn],LOG[maxn],all,n;
	int dp[25][maxn], point[25][maxn];  //2^20 == 1e6  2^25 == 3e7
	vector<node> G[maxn];
	void dfs(int u, int now) {
		path[++all] = u;
		loc[u] = all;
		dep[all] = now;
		for (node cur : G[u]) {
            int v = cur.to;
			if (loc[v]) continue;
			len[v] = now+1;
			dist[v] = dist[u]+cur.w;
			dfs(v, now+1);
			path[++all] = u;
			dep[all] = now;
		}
	}
	void initRMQ(int n)
	{
		LOG[0] = -1;
		for (int i = 1; i <= all; ++i) {
			dp[0][i] = dep[i];
			point[0][i] = path[i];
			LOG[i] = ((i&(i-1)) == 0 ? LOG[i-1]+1 : LOG[i-1]);
		}
        for (int i = 1; (1<<i) <= all; ++i) {
            for (int j = 1; j+(1<<i)-1 <= all; ++j) {
              if (dp[i-1][j] < dp[i-1][j+(1<<(i-1))]) {
                dp[i][j] = dp[i-1][j];
                point[i][j] = point[i-1][j];
              } else {
                dp[i][j] = dp[i-1][j+(1<<(i-1))];
                point[i][j] = point[i-1][j+(1<<(i-1))];
              }
            }
        }
	}
	int queryLCA(int l,int r)
	{
		l = loc[l]; r = loc[r];
		if(l>r) swap(l,r);
		int k = LOG[r-l+1];
		/*
		貌似下面这种写法更快
		记得把上面预处理的LOG删了
		 P 3379
		int k=0;
		while((1<<k)<=r-l+1) k++;
		k--;
		*/
		if(dp[k][l] < dp[k][r-(1<<k)+1]) return point[k][l];
		else return point[k][r-(1<<k)+1];
	}

	type getDist(int a,int b){
	    return dist[a]+dist[b]-2*dist[queryLCA(a,b)];
    }
	int getLen(int a,int b){return len[a]+len[b]-2*len[queryLCA(a,b)];}
	void init(int _n)
	{
		n = _n;
		all = 0;
		for(int i = 0;i <= n; i++)
		{
			loc[i] = 0;
			dist[i] = 0;
			len[i] = 0;
			G[i].clear();
		}
	}
	void addEdge(int a,int b,type w=1)
	{
		G[a].eb(node(b,w));
		G[b].eb(node(a,w));
	}
	void solve(int root)
	{
		dfs(root, 1);
		initRMQ(all);
	}
	#undef type
}lca;

int findRoot(int x) {
    if (x == fa[x]) return x;
    else {
        return (fa[x] = findRoot(fa[x]));
    }
}
void uniRoot(int a, int b) {
    int aa = findRoot(a);
    int bb = findRoot(b);
    if (aa != bb) fa[bb] = aa;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.precision(10);
    cout << fixed;
#ifdef LOCAL_DEFINE
    freopen("input.txt", "r", stdin);
#endif

    while (cin >> n >> m >> q) {
        for (int i = 1; i <= n; ++i) fa[i] = i;
        lca.init(n);
        forn(i, m) {
            int u, v, val;
            cin >> u >> v >> val;
            lca.addEdge(u, v, val);
            lca.addEdge(v, u, val);
            uniRoot(u, v);
        }
        for1(i, n) if (fa[i] == i) lca.solve(i);
        while (q--) {
            int a, b;
            cin >> a >> b;
            if (findRoot(a) != findRoot(b))
                cout << "Not connected" << '\n';
            else {
                cout << lca.getDist(a, b) << '\n';
            }
        }
    }

#ifdef LOCAL_DEFINE
    cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值