• Luogu4886 快递员 点分治


    传送门


    淀粉质好题啊qaq

    我们先考虑随便选择一个点作为邮递中心,通过移动邮递中心找到更优的位置。将路径最大值求出,并将路径最大值对应的那一些路径拿出来考虑。可以知道,如果说这些路径中存在一条经过当前邮递中心的路径,意味着当前点就是最优的(因为不论邮递中心怎么移动,这一条路径的长度不会小于当前值,也就是说答案不会小于当前的最大值),所以只有起点和终点在同一子树内的路径的最长路径才有可能通过移动邮递中心使得答案变得更小。而如果说存在两条路径分布在不同子树内,显然也是无法通过移动使得答案更优的,因为不论邮递中心怎么移动,至少会有一条路径的长度增加。所以只有所有最长路径都在当前邮递中心的一棵子树内的时候,可以通过将邮递中心向子树内移动获得更优的答案。

    但是显然每一次都移动一格的复杂度最坏是$O(nm)$的,我们考虑优化。我们可以借助于点分治的思想,每一次移动不是移动到子树的根的位置,而是跳到这一棵子树的重心的位置递归求解,这样的复杂度就是$O(mlogn)$了。

      1 #include<bits/stdc++.h>
      2 //This code is written by Itst
      3 using namespace std;
      4 
      5 inline int read(){
      6     int a = 0;
      7     bool f = 0;
      8     char c = getchar();
      9     while(c != EOF && !isdigit(c)){
     10         if(c == '-')
     11             f = 1;
     12         c = getchar();
     13     }
     14     while(c != EOF && isdigit(c)){
     15         a = (a << 3) + (a << 1) + (c ^ '0');
     16         c = getchar();
     17     }
     18     return f ? -a : a;
     19 }
     20 
     21 const int MAXN = 100010;
     22 struct Edge{
     23     int end , upEd , w;
     24 }Ed[MAXN << 1];
     25 int head[MAXN] , query[MAXN][2] , dis[MAXN] , size[MAXN] , be[MAXN];
     26 int N , M , cntEd , ans , nowSize , minSize , minInd;
     27 bool vis[MAXN];
     28 
     29 inline void addEd(int a , int b , int c){
     30     Ed[++cntEd].end = b;
     31     Ed[cntEd].upEd = head[a];
     32     Ed[cntEd].w = c;
     33     head[a] = cntEd;
     34 }
     35 
     36 void getSize(int now){
     37     ++nowSize;
     38     vis[now] = 1;
     39     for(int i = head[now] ; i ; i = Ed[i].upEd)
     40         if(!vis[Ed[i].end])
     41             getSize(Ed[i].end);
     42     vis[now] = 0;
     43 }
     44 
     45 void getRoot(int now){
     46     int maxN = 0;
     47     size[now] = vis[now] = 1;
     48     for(int i = head[now] ; i ; i = Ed[i].upEd)
     49         if(!vis[Ed[i].end]){
     50             getRoot(Ed[i].end);
     51             size[now] += size[Ed[i].end];
     52             maxN = max(maxN , size[Ed[i].end]);
     53         }
     54     maxN = max(maxN , nowSize - size[now]);
     55     if(maxN < minSize){
     56         minSize = maxN;
     57         minInd = now;
     58     }
     59     vis[now] = 0;
     60 }
     61 
     62 void getDis(int now , int fa , int cnt , int len){
     63     be[now] = cnt;
     64     dis[now] = len;
     65     for(int i = head[now] ; i ; i = Ed[i].upEd)
     66         if(Ed[i].end != fa)
     67             getDis(Ed[i].end , now , cnt , len + Ed[i].w);
     68 }
     69 
     70 void solve(int now){
     71     nowSize = 0;
     72     minSize = 0x7fffffff;
     73     getSize(now);
     74     getRoot(now);
     75     int root = minInd , cnt = 0 , maxL = 0 , allBe = 0;
     76     vis[root] = 1;
     77     dis[root] = be[root] = 0;
     78     for(int i = head[root] ; i ; i = Ed[i].upEd)
     79         getDis(Ed[i].end , root , ++cnt , Ed[i].w);
     80     for(int i = 1 ; i <= M ; ++i)
     81         maxL = max(maxL , dis[query[i][0]] + dis[query[i][1]]);
     82     ans = min(ans , maxL);
     83     for(int i = 1 ; i <= M ; ++i)
     84         if(dis[query[i][0]] + dis[query[i][1]] == maxL)
     85             if(be[query[i][0]] == be[query[i][1]] && (!allBe || allBe == be[query[i][0]]))
     86                 allBe = be[query[i][0]];
     87             else
     88                 if((!be[query[i][0]] || !be[query[i][1]]) && (!allBe || allBe == be[query[i][0]] + query[i][1]))
     89                     allBe = be[query[i][0]] + be[query[i][1]];
     90                 else
     91                     return;
     92     for(int i = head[root] ; i ; i = Ed[i].upEd)
     93         if(!vis[Ed[i].end] && be[Ed[i].end] == allBe){
     94             solve(Ed[i].end);
     95             return;
     96         }
     97 }
     98 
     99 int main(){
    100     N = read();
    101     M = read();
    102     ans = 2147483647;
    103     for(int i = 1 ; i < N ; ++i){
    104         int a = read() , b = read() , c = read();
    105         addEd(a , b , c);
    106         addEd(b , a , c);
    107     }
    108     for(int i = 1 ; i <= M ; ++i){
    109         query[i][0] = read();
    110         query[i][1] = read();
    111     }
    112     solve(1);
    113     printf("%d" , ans);
    114     return 0;
    115 }
  • 相关阅读:
    348. Design Tic-Tac-Toe
    347. Top K Frequent Elements
    346. Moving Average from Data Stream
    345. Reverse Vowels of a String
    343. Integer Break
    342. Power of Four
    341. Flatten Nested List Iterator
    340. Longest Substring with At Most K Distinct Characters
    339. Nested List Weight Sum
    Python(九) Python的高级语法与用法
  • 原文地址:https://www.cnblogs.com/Itst/p/10074814.html
Copyright © 2020-2023  润新知