• CODEVS 2370 小机房的树


    任意门:http://codevs.cn/problem/2370/

    题目描述 Description

    小机房有棵焕狗种的树,树上有N个节点,节点标号为0到N-1,有两只虫子名叫飘狗和大吉狗,分居在两个不同的节点上。有一天,他们想爬到一个节点上去搞基,但是作为两只虫子,他们不想花费太多精力。已知从某个节点爬到其父亲节点要花费 c 的能量(从父亲节点爬到此节点也相同),他们想找出一条花费精力最短的路,以使得搞基的时候精力旺盛,他们找到你要你设计一个程序来找到这条路,要求你告诉他们最少需要花费多少精力

    输入描述 Input Description
    第一行一个n,接下来n-1行每一行有三个整数u,v, c 。表示节点 u 爬到节点 v 需要花费 c 的精力。
    第n+1行有一个整数m表示有m次询问。接下来m行每一行有两个整数 u ,v 表示两只虫子所在的节点
    输出描述 Output Description

    一共有m行,每一行一个整数,表示对于该次询问所得出的最短距离。

    样例输入 Sample Input

    3

    1 0 1

    2 0 1

    3

    1 0

    2 0

    1 2

    样例输出 Sample Output

    1

    1

    2

    数据范围及提示 Data Size & Hint

    1<=n<=50000, 1<=m<=75000, 0<=c<=1000

    题意概括:

    需要注意一点是给的边的信息是先给子节点再给父亲结点。

    解题思路:

    DFS预处理各个结点到树的根结点的距离(如果建双向边要判重)

    Tarjan 找出最近公共祖先,老套路(如果建双向边要判重)

    TIP:

    这些题目要注意找根结点(建单向边的时候),如果搞不清楚谁是子节点谁是父亲结点,建双向边,操作时判重一下即可。

    AC code:

      1 #include <cstdio>
      2 #include <iostream>
      3 #include <cstring>
      4 #include <algorithm>
      5 #include <vector>
      6 #define INF 0x3f3f3f3f
      7 #define LL long long
      8 using namespace std;
      9 const int MAX_N = 5e4+5;
     10 const int MAX_M = 8e4;
     11 struct Edge{int v, w, nxt;}edge[MAX_N<<1];
     12 struct Query
     13 {
     14     int v, id;
     15     Query(){};
     16     Query(int _v,int _id):v(_v),id(_id){};
     17 };
     18 vector<Query> q[MAX_N];
     19 
     20 int head[MAX_N], cnt;
     21 int dis[MAX_N];
     22 int fa[MAX_N];
     23 bool vis[MAX_N];
     24 bool in[MAX_N];
     25 int ans[MAX_M];
     26 int N, M;
     27 
     28 void init()
     29 {
     30     memset(head, -1, sizeof(head));
     31     memset(dis, 0, sizeof(dis));
     32     memset(vis, false, sizeof(vis));
     33     memset(in, false, sizeof(in));
     34     memset(ans, 0, sizeof(ans));
     35     cnt = 0;
     36 }
     37 
     38 void AddEdge(int from, int to, int weight)
     39 {
     40     edge[cnt].v = to;
     41     edge[cnt].w = weight;
     42     edge[cnt].nxt = head[from];
     43     head[from] = cnt++;
     44 }
     45 
     46 int getfa(int x){return fa[x]==x?x:fa[x] = getfa(fa[x]);}
     47 /*
     48 int getfa(int x)                                        //找祖先
     49 {
     50     int root = x;
     51     while(fa[root] != root) root = fa[root];
     52 
     53     int tmp;
     54     while(fa[x] != root){
     55         tmp = fa[x];
     56         fa[x] = root;
     57         x = tmp;
     58     }
     59     return root;
     60 }
     61 */
     62 void dfs(int s, int f)
     63 {
     64     for(int i = head[s]; i != -1; i = edge[i].nxt){
     65         //if(edge[i].v == f) continue;              //如果建双向边要去重
     66         dis[edge[i].v] = dis[s] + edge[i].w;
     67         dfs(edge[i].v, s);
     68     }
     69 }
     70 
     71 void Tarjan(int s, int f)
     72 {
     73     int root = s;
     74     fa[s] = s;
     75     for(int i = head[s]; i != -1; i = edge[i].nxt){
     76         int Eiv = edge[i].v;
     77         //if(Eiv == f) continue;        //如果建双向边要去重
     78         Tarjan(Eiv, root);
     79         fa[getfa(Eiv)] = s;
     80     }
     81     vis[s] = true;
     82     for(int i = 0; i < q[s].size(); i++){
     83         if(vis[q[s][i].v] && !ans[q[s][i].id]){
     84             ans[q[s][i].id] = dis[q[s][i].v] + dis[s] - 2*dis[getfa(q[s][i].v)];
     85         }
     86     }
     87 }
     88 
     89 int main()
     90 {
     91     init();
     92     scanf("%d", &N);
     93     for(int i = 1, u, v, w; i < N; i++){
     94         //scanf("%d %d %d", &u, &v, &w);    //建双向边
     95         scanf("%d %d %d", &v, &u, &w);
     96         AddEdge(u, v, w);
     97         //AddEdge(v, u, w);         //建双向边
     98         in[v] = true;
     99     }
    100     scanf("%d", &M);
    101     for(int i = 1, u, v; i <= M; i++){
    102         scanf("%d %d", &u, &v);
    103         q[u].push_back(Query(v, i));
    104         q[v].push_back(Query(u, i));
    105     }
    106 
    107     int root = 0;
    108     for(int i = 0; i < N; i++) if(!in[i]){root = i; break;}
    109 
    110     dfs(root, -1);
    111     Tarjan(root, -1);
    112 
    113     for(int i = 1; i <= M; i++){
    114         printf("%d
    ", ans[i]);
    115     }
    116     return 0;
    117 }
  • 相关阅读:
    ES6知识点整理之----解构赋值----对象
    ES6知识点整理之----解构赋值----数组
    ES6知识点整理之----声明变量总结与global
    ES6知识点整理之----const
    ES6知识点整理之----块级作用域
    ES6知识点整理之----let
    ES6知识点整理之----历史及简介
    推荐大家使用的CSS书写规范、顺序
    meta标签补充属性(viewport)
    meta标签属性总结
  • 原文地址:https://www.cnblogs.com/ymzjj/p/9744869.html
Copyright © 2020-2023  润新知