zoukankan      html  css  js  c++  java
  • [APIO2010]巡逻

    嘟嘟嘟


    这题有点意思。


    手玩得知,连上一条边后,形成的环只用走一次,剩下的还要走两次。
    因此(k = 1)就是求树的直径。
    (k = 2)怎么办咧?也是先求一遍树的直径,然后我就想,连上端点后就变成了一个基环树,我们要在这个基环树上再连一条边,使(新形成的环的长度)-(与原环相交长度)尽可能大。
    这就很头疼了,刚开始我想分两种情况:一是外向树内部求一个直径,取最大值;二是对于每一个外向树dp求最长链,然后两两组合。这两者再取一个较大值作为答案。但第二种情况是(O(n ^ 2))的。
    最后还是看了题解。题解确实很妙:因为相交的部分会从原来的走一遍变成走两遍,因此我们把原环上的边都置为-1,然后再求一遍树的直径,就是新环的长度-1了!这样我们再减去新环的长度,-1的部分就变成了+1,就相当于走了两遍。


    第一遍求直径为了找端点,就两边dfs;第二遍有负权,只能树形dp。


    更新!!:
    刚刚又翻了一篇题解,发现我自己yy的那个方法是可行的。(O(n ^ 2))部分改成用单调队列维护就好啦!!

    #include<cstdio>
    #include<iostream>
    #include<cmath>
    #include<algorithm>
    #include<cstring>
    #include<cstdlib>
    #include<cctype>
    #include<vector>
    #include<stack>
    #include<queue>
    #include<map>
    using namespace std;
    #define enter puts("") 
    #define space putchar(' ')
    #define Mem(a, x) memset(a, x, sizeof(a))
    #define In inline
    typedef long long ll;
    typedef double db;
    const int INF = 0x3f3f3f3f;
    const db eps = 1e-8;
    const int maxn = 1e5 + 5;
    inline ll read()
    {
      ll ans = 0;
      char ch = getchar(), last = ' ';
      while(!isdigit(ch)) last = ch, ch = getchar();
      while(isdigit(ch)) ans = (ans << 1) + (ans << 3) + ch - '0', ch = getchar();
      if(last == '-') ans = -ans;
      return ans;
    }
    inline void write(ll x)
    {
      if(x < 0) x = -x, putchar('-');
      if(x >= 10) write(x / 10);
      putchar(x % 10 + '0');
    }
    
    int n, K;
    struct Edge
    {
      int nxt, to;
    }e[maxn << 1];
    int head[maxn], ecnt = -1;
    In void addEdge(int x, int y)
    {
      e[++ecnt] = (Edge){head[x], y};
      head[x] = ecnt;
    }
    
    int dep[maxn], fa[maxn], Max = 0, A, B;
    In void dfs1(int now, int _f, int dis, int& id)
    {
      if(dis > Max) Max = dis, id = now;
      dep[now] = dep[_f] + 1, fa[now] = _f;
      for(int i = head[now], v; ~i; i = e[i].nxt)
        {
          if((v = e[i].to) == _f) continue;
          dfs1(v, now, dis + 1, id);
        }
    }
    
    #define pr pair<int, int>
    #define mp make_pair
    map<pr, bool> Mp;
    
    int dp[maxn], ans = 0;
    In void dfs2(int now, int _f)
    {
      int Max1 = 0, Max2 = 0;
      for(int i = head[now], v; ~i; i = e[i].nxt)
        {
          if((v = e[i].to) == _f) continue;
          dfs2(v, now);
          int x = now, y = v;
          if(x > y) swap(x, y);
          int w = Mp.count(mp(x, y)) ? -1 : 1;
          if(dp[v] + w > Max1) Max2 = Max1, Max1 = dp[v] + w;
          else if(dp[v] + w > Max2) Max2 = dp[v] + w;
        }
      ans = max(ans, Max1 + Max2);
      dp[now] = Max1;
    }
    
    int main()
    {
      Mem(head, -1);
      n = read(); K = read();
      for(int i = 1; i < n; ++i)
        {
          int x = read(), y = read();
          addEdge(x, y), addEdge(y, x);
        }
      dfs1(1, 0, 0, A), Max = 0, dfs1(A, 0, 0, B);
      if(K == 1) {write((n << 1) - Max - 1), enter; return 0;}
      while(A ^ B)
        {
          if(dep[A] < dep[B]) swap(A, B);
          int x = A, y = fa[A];
          if(x > y) swap(x, y);
          Mp[mp(x, y)] = 1;
          A = fa[A];
        }
      dfs2(1, 0);
      write((n << 1) - Max - ans), enter;
      return 0;
    }
    
  • 相关阅读:
    Window 窗口类
    使用 Bolt 实现 GridView 表格控件
    lua的table库
    Windows编程总结之 DLL
    lua 打印 table 拷贝table
    使用 xlue 实现简单 listbox 控件
    使用 xlue 实现 tips
    extern “C”
    COleVariant如何转换为int double string cstring
    原来WIN32 API也有GetOpenFileName函数
  • 原文地址:https://www.cnblogs.com/mrclr/p/10791115.html
Copyright © 2011-2022 走看看