首页 > 技术文章 > codeforces 427 div.2 F. Roads in the Kingdom

orz010orz 2017-08-09 19:34 原文

time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

In the Kingdom K., there are n towns numbered with integers from 1 to n. The towns are connected by n bi-directional roads numbered with integers from 1 to n. The i-th road connects the towns ui and vi and its length is li. There is no more than one road between two towns. Also, there are no roads that connect the towns with itself.

Let's call the inconvenience of the roads the maximum of the shortest distances between all pairs of towns.

Because of lack of money, it was decided to close down one of the roads so that after its removal it is still possible to reach any town from any other. You have to find the minimum possible inconvenience of the roads after closing down one of the roads.

Input

The first line contains the integer n (3 ≤ n ≤ 2·105) — the number of towns and roads.

The next n lines contain the roads description. The i-th from these lines contains three integers ui, vi, li (1 ≤ ui, vi ≤ n, 1 ≤ li ≤ 109) — the numbers of towns connected by the i-th road and the length of the i-th road. No road connects a town to itself, no two roads connect the same towns.

It's guaranteed that it's always possible to close down one of the roads so that all the towns are still reachable from each other.

Output

Print a single integer — the minimum possible inconvenience of the roads after the refusal from one of the roads.

Examples
Input
3
1 2 4
2 3 5
1 3 1
Output
5
Input
5
2 3 7
3 1 9
4 1 8
3 5 4
4 5 5
Output
18

 

 

 

题意 :

  给定n个点 n条边 (保证联通 ,边无向 ,无重边 ,无自环) 

  断掉某条边以后 保证联通的情况下,图上有一条最长路

  求最长路的最小值

思路 :

  n个联通的点 n条边  

  即 树上多了一个环

  断掉的边只能在环上

  所以 题意转化为 从环上断掉一个点以后 树上直径的最小化

  首先 dfs 找出环

  然后得到非环上边的最长路(求以环上点为根的子树直径)

  之后得到环上点到其子树的最长路 记为 点  i  的权值  val [ i ] 

  样例二:  

      

  得到 当前最长直径是 点 3 的子树  长度为 7   记录下来为   L1  (我在这里错了几次)

  得到每个点的权值   

              val   [ 1 ]  =    0

              val   [ 3 ]  =    7

              val   [ 4 ]  =    0

              val   [ 5 ]  =    0

 

       然后得到环上的 前缀路径和 与后缀路径和

  point     1  ->  3  ->   5  ->  4  ->  1  ->  3  ->  5  ->  4

  road         9        4        5       8       9       4        5

  pre- >    0       9        13     18     26      35     39       44  ->

  suf <-   44       35        31      26      18        9       5       0   <-

 

  然后  容易知道  到点 i  的  “前缀和”+ “点权值”  (pre [ i ] + val [ i ])  表示  环上第一个点(上图中为1)到 i 的 子树的最长路径

  由于  “树上 离任意一点最远的一定是  直径的某个端点” 

  这样由区间最大值就可以得到 一个直径端点   然后往 “前面” 和 “后面” 找到 离端点最远的另一个点 就是直径的第二个端点 

  每次的区间大小为环的长度 (表示断掉一条边以后的路径前缀和) 每次向右移动一次 得到 第二个直径  并更新 ans   

  区间最大值的维护可以通过线段树      维护一个前缀的  一个后缀的    

  最后答案输出 max(ans,L1)  即可

  

     

  1 #include <bits/stdc++.h>
  2 
  3 #define mp make_pair
  4 #define pb push_back
  5 #define lson l,mid,pos<<1
  6 #define rson mid+1,r,pos<<1|1
  7 #define fi first
  8 #define se second
  9 
 10 using namespace std;
 11 
 12 typedef long long LL;
 13 typedef pair<long long ,int> pli;
 14 
 15 const long long INF = 0x3f3f3f3f3f3f3f3f;
 16 
 17 vector <int > nt[423456];
 18 vector <int > cc[423456];
 19 int noloop[423456];
 20 int cnt[423456];
 21 LL val[423456];
 22 LL toval[423456];
 23 LL id[423456];
 24 int idfrm[423456];
 25 pli tree1[420000<<2];
 26 pli tree2[420000<<2];
 27 LL pre[423456];
 28 LL suf[423456];
 29 int mark=1;
 30 LL zz010=0;
 31 void dfs1(int x,int fa)
 32 {
 33     noloop[x]=1;
 34     for (int i=0;i<nt[x].size();i++){
 35         if (fa==nt[x][i])continue;
 36         cnt[nt[x][i]]--;
 37         if (cnt[nt[x][i]]==1)dfs1(nt[x][i],x);
 38     }
 39 }
 40 LL dfs2(int x,int fa)
 41 {
 42     LL ret=0;
 43     LL ret2=0;
 44     for (int i=0;i<nt[x].size();i++){
 45         if (fa==nt[x][i]||noloop[nt[x][i]]==0)continue;
 46         LL tmp=dfs2(nt[x][i],x)+cc[x][i];
 47         if (tmp>ret){
 48             ret2=ret;
 49             ret=tmp;
 50         }else if (tmp>ret2)ret2=tmp;
 51     }
 52     zz010=max(zz010,ret+ret2);
 53     return val[x]=ret;
 54 }
 55 void dfs3(int x,int fa)
 56 {
 57     idfrm[mark]=x;
 58     id[x]=mark;
 59     for (int i=0;i<nt[x].size();i++){
 60         if (noloop[nt[x][i]]||nt[x][i]==fa||id[nt[x][i]])continue;
 61         toval[mark++]=cc[x][i];
 62         dfs3(nt[x][i],x);
 63         return ;
 64     }
 65     for (int i=0;i<nt[x].size();i++){
 66         if (id[nt[x][i]]!=1)continue;
 67         toval[mark]=cc[x][i];
 68         return ;
 69     }
 70 }
 71 void push_up(pli tree[],int pos)
 72 {
 73     tree[pos]=max(tree[pos<<1],tree[pos<<1|1]);
 74 }
 75 void upd(pli tree[],int l,int r,int pos,int x,long long val)
 76 {
 77     if (l==r){
 78         tree[pos].fi=val;
 79         tree[pos].se=x;
 80         return ;
 81     }
 82     int mid=(l+r)>>1;
 83     if (x<=mid)upd(tree,lson,x,val);
 84     else upd(tree,rson,x,val);
 85     push_up(tree,pos);
 86 }
 87 pli query(pli tree[],int l,int r,int pos,int l1,int r1)
 88 {
 89     if (l1>r1)return mp(-INF,0);
 90     if (l>=l1&&r1>=r){
 91         return tree[pos];
 92     }
 93     pli mx=mp(-INF,0);
 94     int mid=(l+r)>>1;
 95     if (mid>=l1)mx=query(tree,lson,l1,r1);
 96     if (mid+1<=r1)mx=max(mx,query(tree,rson,l1,r1));
 97     return mx;
 98 }
 99 int main()
100 {
101     int n;
102     scanf("%d",&n);
103     int a,b;
104     long long v;
105     for (int i=0;i<n;i++){
106         scanf("%d%d%I64d",&a,&b,&v);
107         nt[a].pb(b);
108         nt[b].pb(a);
109         cc[a].pb(v);
110         cc[b].pb(v);
111         cnt[a]++;
112         cnt[b]++;
113     }
114     for (int i=1;i<=n;i++){
115         if (nt[i].size()==1)dfs1(i,-1);
116     }
117     for (int i=1;i<=n;i++){
118         if (noloop[i]==0)dfs2(i,-1);
119     }
120     for (int i=1;i<=n;i++){
121         if (!noloop[i]){
122             dfs3(i,-1);
123             break;
124         }
125     }
126     long long tmp=0;
127     for (int i=1;i<=mark;i++){
128         idfrm[i+mark]=idfrm[i];
129         toval[i+mark]=toval[i];
130     }
131     toval[0]=toval[mark];
132     for (int i=1;i<=2*mark;i++){
133         pre[i]=pre[i-1]+toval[i-1];
134         upd(tree1,1,2*mark,1,i,val[idfrm[i]]+pre[i]);
135     }
136     for (int i=2*mark;i>=1;i--){
137         suf[i]=suf[i+1]+toval[i];
138         upd(tree2,1,2*mark,1,i,val[idfrm[i]]+suf[i]);
139     }
140     LL ans=INF;
141     int flag=0;
142     for (int i=1;i<=mark;i++){
143         pli now_mx=query(tree1,1,2*mark,1,i,i+mark-1);
144         pli tmp1=query(tree1,1,2*mark,1,now_mx.se+1,i+mark-1);
145         pli tmp2=query(tree2,1,2*mark,1,i,now_mx.se-1);
146         LL dis1=0LL,dis2=0LL,dis3=0,dis4=0;
147         if (tmp1.se!=0)dis1=val[idfrm[now_mx.se]]+val[idfrm[tmp1.se]]+pre[tmp1.se]-pre[now_mx.se];
148         if (tmp2.se!=0)dis2=val[idfrm[now_mx.se]]+val[idfrm[tmp2.se]]-pre[tmp2.se]+pre[now_mx.se];
149         ans=min(ans,max(dis1,dis2));
150     }151     cout<<max(ans,zz010);
152     return 0;
153 }

最后   数组记得开大点   前缀和与后缀和  为 环上点数量的两倍

  

 

推荐阅读