zoj 3195 Design the city

1 篇文章 0 订阅

题意:找无向树上三个点间的距离

题解:在线lca,开始是想分情况讨论,后来发现可以通过求3对两点间距离除以2来求得答案,感觉是一种尝试将问

题规模变小的思想吧。

总结:这个题因为小错改了好久好久才改出来,以后规定自己纯改错时间不得超过20分钟!

下面贴出两种lca转rmq的实现方法

#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
using namespace std;
typedef pair<int,int>pii;
#define MAXN 151000
#define LOG 20
int rmq[MAXN][LOG],s[MAXN],place[MAXN],id[MAXN],deep[MAXN];
int cnt,vs;
vector<pii>vec[MAXN];
void dfs(int u,int fa,int val)
{
    for(int i = 0;i < vec[u].size();i++)
    {
        int v = vec[u][i].first,w = vec[u][i].second;
        if(v == fa)continue;
        s[v] = val + w;
        id[++cnt] = v;
        rmq[++vs][0] = cnt;
        place[v] = vs;
        dfs(v,u,val + w);
        rmq[++vs][0] = rmq[place[u]][0];
    }
}
void init_rmq()
{
    for(int j = 1;(1 << j) <= vs + 1;j++)
        for(int i = 0;i <= vs;i++)
            rmq[i][j] = min(rmq[i][j - 1],rmq[i + (1 << (j - 1))][j - 1]);
}
int query(int a,int b)
{
    a = place[a],b = place[b];
    if(a > b)swap(a,b);
    int len = -1;
    while(b - a + 1 >= (1 << (len + 1)))
        len++;
    return id[min(rmq[a][len],rmq[b - (1 << len) + 1][len])];
}
int main()
{
    int n,u,v,w,_ = 0,q;
    while(scanf("%d",&n) != EOF)
    {
        if(_++)puts("");
        for(int i = 0;i < n;i++)vec[i].clear();
        for(int i = 1;i < n;i++)
        {
            scanf("%d%d%d",&u,&v,&w);
            vec[u].push_back(pii(v,w));
            vec[v].push_back(pii(u,w));
        }
        cnt = vs = 0;
        dfs(0,-1,0);
        init_rmq();
        scanf("%d",&q);
        while(q--)
        {
            scanf("%d%d%d",&u,&v,&w);
            int ans1 = s[u] + s[v] - (s[query(u,v)] << 1);
            int ans2 = s[u] + s[w] - (s[query(u,w)] << 1);
            int ans3 = s[v] + s[w] - (s[query(v,w)] << 1);
            printf("%d\n",(ans1 + ans2 + ans3) >> 1);
        }
    }
}




#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
using namespace std;
typedef pair<int,int>pii;
#define MAXN 151000
#define LOG 20
int rmq[MAXN][LOG],s[MAXN],place[MAXN],deep[MAXN];
int cnt,vs;
vector<pii>vec[MAXN];
void dfs(int u,int fa,int d,int val)
{
    for(int i = 0;i < vec[u].size();i++)
    {
        int v = vec[u][i].first,w = vec[u][i].second;
        if(v == fa)continue;
        deep[v] = d;
        s[v] = val + w;
        rmq[++vs][0] = v;
        place[v] = vs;
        dfs(v,u,d + 1,val + w);
        rmq[++vs][0] = u;
    }
}
void init_rmq()
{
    for(int j = 1;(1 << j) <= vs + 1;j++)
        for(int i = 0;i <= vs;i++)
        {
            int d1 = deep[rmq[i][j - 1]];
            int d2 = deep[rmq[i + (1 << (j - 1))][j - 1]];
            if(d1 < d2)rmq[i][j] = rmq[i][j - 1];
            else rmq[i][j] = rmq[i + (1 << (j - 1))][j - 1];
        }
}
int query(int a,int b)
{
    a = place[a],b = place[b];
    if(a > b)swap(a,b);
    int len = -1;
    while(b - a + 1 >= (1 << (len + 1)))
        len++;
    int d1 = deep[rmq[a][len]];
    int d2 = deep[rmq[b - (1 << len) + 1][len]];
    if(d1 < d2)return rmq[a][len];
    else return rmq[b - (1 << len) + 1][len];
}
int main()
{
    int n,u,v,w,_ = 0,q;
    while(scanf("%d",&n) != EOF)
    {
        if(_++)puts("");
        for(int i = 0;i < n;i++)vec[i].clear();
        for(int i = 1;i < n;i++)
        {
            scanf("%d%d%d",&u,&v,&w);
            vec[u].push_back(pii(v,w));
            vec[v].push_back(pii(u,w));
        }
        cnt = vs = 0;
        dfs(0,-1,1,0);
        init_rmq();
        scanf("%d",&q);
        while(q--)
        {
            scanf("%d%d%d",&u,&v,&w);
            int ans1 = s[u] + s[v] - (s[query(u,v)] << 1);
            int ans2 = s[u] + s[w] - (s[query(u,w)] << 1);
            int ans3 = s[v] + s[w] - (s[query(v,w)] << 1);
            printf("%d\n",(ans1 + ans2 + ans3) / 2);
        }
    }
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值