树上倍增

题目描述

A 国有 nn 座城市,编号从 11 到 nn,城市之间有 mm 条双向道路。每一条道路对车辆都有重量限制,简称限重。

现在有 qq 辆货车在运输货物, 司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物。

输入格式

第一行有两个用一个空格隔开的整数 n,mn,m,表示 AA 国有 nn 座城市和 mm 条道路。

接下来 mm 行每行三个整数 x, y, zx,y,z,每两个整数之间用一个空格隔开,表示从 xx 号城市到 yy 号城市有一条限重为 zz 的道路。
注意: x \neq yx​=y,两座城市之间可能有多条道路 。

接下来一行有一个整数 qq,表示有 qq 辆货车需要运货。

接下来 qq 行,每行两个整数 x,yx,y,之间用一个空格隔开,表示一辆货车需要从 xx 城市运输货物到 yy 城市,保证 x \neq yx​=y

输出格式

共有 qq 行,每行一个整数,表示对于每一辆货车,它的最大载重是多少。
如果货车不能到达目的地,输出 -1−1。

输入输出样例

输入 #1复制

4 3
1 2 4
2 3 3
3 1 1
3
1 3
1 4
1 3

输出 #1复制

3
-1
3

说明/提示

对于 30\%30% 的数据,1 \le n < 10001≤n<1000,1 \le m < 10,0001≤m<10,000,1\le q< 10001≤q<1000;

对于 60\%60% 的数据,1 \le n < 10001≤n<1000,1 \le m < 5\times 10^41≤m<5×104,1 \le q< 10001≤q<1000;

对于 100\%100% 的数据,1 \le n < 10^41≤n<104,1 \le m < 5\times 10^41≤m<5×104,1 \le q< 3\times 10^41≤q<3×104,0 \le z \le 10^50≤z≤105。

这个题目我没有看板子ac的。

#include
using namespace std;
const int maxn = 10010;
const int inf = 0x3f3f3f3f;
struct node
{
    int x, y, z;
} N[maxn * 5 + 10];
vector > V[maxn];
int f[maxn], anc[maxn][(int)log2(maxn)], dis[maxn][(int)log2(maxn)], Dep[maxn],vis[maxn];
void init(int n)
{
    for (int i = 0; i <= n; i++)
        f[i] = i;
    memset(anc, 0, sizeof(anc));
    memset(dis, inf, sizeof(dis));
    memset(Dep, 0, sizeof(Dep));
    memset(vis,0,sizeof(vis));
}
int Find(int x)
{
    return f[x] == x ? x : (f[x] = Find(f[x]));
}
void Merge(int x, int y)
{
    int X = Find(x);
    int Y = Find(y);
    f[X] = Y;
    return;
}
void dfs(int x, int dep)
{
    vis[x]=1;
    for(auto it =V[x].begin(); it!=V[x].end(); it++)
    {
        if(vis[(*it).first])
            continue;
        anc[(*it).first][0] = x;
        dis[(*it).first][0] = (*it).second;
        Dep[(*it).first] = dep+1;
        for (int i = 1; i <=(int)log2(dep+1); i++)
        {
            anc[(*it).first][i] = anc[anc[(*it).first][i-1]][i - 1];
            dis[(*it).first][i] = min(dis[(*it).first][i - 1], dis[anc[(*it).first][i-1]][i - 1]);
        }
        dfs((*it).first, dep + 1);
    }
    return;
}
int solve(int x, int y)
{
    if (Find(x) != Find(y))
        return -1;
    int ans = inf;
    if (Dep[x] < Dep[y])
        swap(x, y);
    int C = Dep[x] - Dep[y];
    for (int i = 0; i <=(int)log2(C); i++)
    {
        if (((1 << i) & C))
        {
            ans = min(ans, dis[x][i]);
            x = anc[x][i];
        }
    }
    if (x != y)
        for (int i =(int)(log2(Dep[x])); i >= 0; i--)
        {
            if(i==0)
            {
                ans = min(min(ans, dis[x][i]), dis[y][i]);
                x = anc[x][i];
                y = anc[y][i];
            }
            else
            {
                if (anc[x][i]!=anc[y][i])
                {
                    ans = min(min(ans, dis[x][i]), dis[y][i]);
                    x = anc[x][i];
                    y = anc[y][i];
                }
            }
        }
    if(x!=y)
        ans= min(ans,min(dis[x][0],dis[y][0]));
    return ans;
}
int main()
{
    int n, m, q;
    cin >> n >> m;
    init(n);
    for (int i = 0; i < m; i++)
    {
        cin >> N[i].x >> N[i].y >> N[i].z;
    }
    sort(N, N + m, [=](node a, node b)
    {
        return a.z > b.z ;
    });
    for (int i = 0; i < m; i++)
    {
        if (Find(N[i].x) != Find(N[i].y))
        {
            Merge(N[i].x, N[i].y);
            V[N[i].x].push_back(make_pair(N[i].y, N[i].z));
            V[N[i].y].push_back(make_pair(N[i].x, N[i].z));
        }
    }
    for (int i = 1; i <= n; i++)
    {
        if (vis[i])
            continue;
        dfs(i, 0);
    }
    int x, y;
    cin>>q;
    while (q--)
    {
        cin >> x >> y;
        cout << solve(x, y) << endl;
    }
}
/*
5 6
1 2 1
2 3 2
3 6 3
1 4 1
4 5 2
5 7 3
100
3 5
6 7

*/

 

你可能感兴趣的:(倍增)