• F. Journey


    题目链接:这儿

    题目大意:给一棵树T,每条边都有一个权值,然后又一条新增边,多次询问:从点x到点y在T上走的最短距离,在加上那条新增边之后,最短距离可以减少多少。

    思路:任意确定一个根root,DFS计算每个点到根的距离dis[],然后每两点间的最短距离为 dis[x]+dis[y]-2*dis[LCA(x,y)]。若新加入一条边u--v,那么如果我们必须经过u--v,那么从x到y的最短距离就为 dis(x,u)+dis(u,v)+dis(v,y)或dis(x,v)+dis(v,u)+dis(u,y)。这样在线处理答案就行。

    PS:至于求LCA的方法可以参考2007年郭华阳的论文《RMQ&LCA问题》,RMQ可以用ST算法,至于那个O(n)的±1RMQ有空再写把……

    AC Code:

      1 #include <cstdio>
      2 #include <cstring>
      3 #include <algorithm>
      4 using namespace std;
      5  
      6 const int MAXN = 300010;
      7 const int MAXM = MAXN * 2;
      8  
      9 int head[MAXN];
     10 int next[MAXM], to[MAXM], cost[MAXM];
     11 int ecnt, root;
     12  
     13 void init() {
     14     ecnt = 1;
     15     memset(head, 0, sizeof(head));
     16 }
     17  
     18 void addEdge(int u, int v, int c) {
     19     to[ecnt] = v; cost[ecnt] = c; next[ecnt] = head[u]; head[u] = ecnt++;
     20     to[ecnt] = u; cost[ecnt] = c; next[ecnt] = head[v]; head[v] = ecnt++;
     21 }
     22  
     23 int dis[MAXN];
     24  
     25 void dfs(int f, int u, int di) {
     26     dis[u] = di;
     27     for(int p = head[u]; p; p = next[p]) {
     28         if(to[p] == f) continue;
     29         dfs(u, to[p], di + cost[p]);
     30     }
     31 }
     32  
     33 int RMQ[2*MAXN], mm[2*MAXN], best[20][2*MAXN];
     34  
     35 void initRMQ(int n) {
     36     int i, j, a, b;
     37     mm[0] = -1;
     38     for(i = 1; i <= n; ++i)
     39        mm[i] = ((i&(i-1)) == 0) ? mm[i-1] + 1 : mm[i-1];
     40     for(i = 1; i <= n; ++i) best[0][i] = i;
     41     for(i = 1; i <= mm[n]; ++i) {
     42         for(j = 1; j <= n + 1 - (1 << i); ++j) {
     43           a = best[i - 1][j];
     44           b = best[i - 1][j + (1 << (i - 1))];
     45           if(RMQ[a] < RMQ[b]) best[i][j] = a;
     46           else best[i][j] = b;
     47         }
     48     }
     49 }
     50  
     51 int askRMQ(int a,int b) {
     52     int t;
     53     t = mm[b - a + 1]; b -= (1 << t)-1;
     54     a = best[t][a]; b = best[t][b];
     55     return RMQ[a] < RMQ[b] ? a : b;
     56 }
     57  
     58 int dfs_clock, num[2*MAXN], pos[MAXN];//LCA
     59  
     60 void dfs_LCA(int f, int u, int dep) {
     61     pos[u] = ++dfs_clock;
     62     RMQ[dfs_clock] = dep; num[dfs_clock] = u;
     63     for(int p = head[u]; p; p = next[p]) {
     64         if(to[p] == f) continue;
     65         dfs_LCA(u, to[p], dep + 1);
     66         ++dfs_clock;
     67         RMQ[dfs_clock] = dep; num[dfs_clock] = u;
     68     }
     69 }
     70  
     71 int LCA(int u, int v) {
     72     if(pos[u] > pos[v]) swap(u, v);
     73     return num[askRMQ(pos[u], pos[v])];
     74 }
     75  
     76 void initLCA(int n) {
     77     dfs_clock = 0;
     78     dfs_LCA(0, root, 0);
     79     initRMQ(dfs_clock);
     80 }
     81  
     82 inline int _abs(const int &x) {
     83     return x > 0 ? x : -x;
     84 }
     85  
     86 int mindis(int x, int y) {
     87     return dis[x] + dis[y] - 2 * dis[LCA(x, y)];
     88 }
     89  
     90 int main() {
     91     int T, n, Q;
     92     int x, y, z, p;
     93     int u, v;
     94     scanf("%d", &T);
     95     for(int t = 1; t <= T; ++t) {
     96         printf("Case #%d:
    ", t);
     97         scanf("%d%d", &n, &Q);
     98         init();
     99         for(int i = 0; i < n - 1; ++i) {
    100             scanf("%d%d%d", &x, &y, &z);
    101             addEdge(x, y, z);
    102         }
    103         scanf("%d%d%d", &x, &y, &z);
    104         root = x;
    105         dis[root] = 0;
    106         for(p = head[root]; p; p = next[p]) dfs(root, to[p], cost[p]);
    107         initLCA(n);
    108         while(Q--) {
    109             scanf("%d%d", &u, &v);
    110             int ans1 = mindis(u, v);
    111             int ans2 = min(mindis(u, x) + mindis(y, v), mindis(u, y) + mindis(x, v)) + z;
    112             if(ans1 > ans2) printf("%d
    ", ans1 - ans2);
    113             else printf("0
    ");
    114         }
    115     }
    116 }

    By Oyking

  • 相关阅读:
    学习Python必须要会的知识,在字符串、列表、元组三者之间相互转换的方法
    python字符串中strip() 函数和 split() 函数的详解
    学习Python必须要知道的4个内置函数
    腾讯轻云服务器,如何使用Windows2016、2019
    jenkins 配置git选分支拉取代码
    查看mysql二进制文件(binlog文件)【报错+解决办法】
    apollo源码部署
    Maven镜像仓库替换为阿里云镜像仓库
    gitlab 日志相关
    gitlab本地搭建后用户(默认)头像不显示问题
  • 原文地址:https://www.cnblogs.com/scnuacm/p/3221291.html
Copyright © 2020-2023  润新知