【NOI2013】快餐店 环套树+线段树

题目大意:给你一颗环套树,你要在这棵的边上(包括端点)找一个点,使得离该点最远的点最近。

数据范围:$n≤10^5$,边权$≤10^9$。

此题不难看出一种暴力做法,我们依次断开环上的一条边,然后求整颗树的直径,取个$min$就好了,时间复杂度是$O(n^2)$的。

然而显然会$T$,我们考虑一些优秀的做法,我们首先将环拆成链,将链倍长(通用套路),然后将环上的点重新编号一下,设环上点的个数为$m$。

如果我们去掉了这个环,原图会变成森林,对于森林中的每一棵树,我们都先求一下它的直径。

令$D_i$表示以环上第$i$个点为根的子树内,与$i$号点距离最大的点与$i$号点间的距离。

令$S_i$表示环上第$i$个点距离环上第一个点的距离(此处的i可以从$1$取到$2m$)。

那么,对于环上两点$(i,j)$,由$i$为根子树,$j$为根子树,还有i至j的链构成的树的直径为$D_i+D_j-S_i+S_j$。

移项后有$(D_i-S_i)+(D_j+S_j)$。

我们用线段树维护这个东西就可以了,(我的线段树写得有点挫,应该有更高效的编码方法)

  1 #include<bits/stdc++.h>
  2 #define M 200005
  3 #define L long long
  4 #define INF (1LL<<60)
  5 #define mid ((a[x].l+a[x].r)/2)
  6 using namespace std;
  7 
  8 struct edge{L u,v,next;}e[M*2]={0}; L head[M]={0},use=0;
  9 void add(L x,L y,L z){use++;e[use].u=y;e[use].v=z;e[use].next=head[x];head[x]=use;}
 10 
 11 struct node{L l,r;L tag,tag2,mx,mx2,ans;}a[M<<2]={0};
 12 void build(L x,L l,L r){
 13     a[x].l=l; a[x].r=r; a[x].ans=a[x].mx=a[x].mx2=-INF; if(l==r) return;
 14     build(x<<1,l,mid); build(x<<1|1,mid+1,r);
 15 }
 16 void upd(L x,L k){
 17     a[x].tag+=k; a[x].mx+=k;
 18     if(a[x].l!=a[x].r) a[x].ans=max(max(a[x<<1].mx+a[x<<1|1].mx2,a[x<<1].mx2+a[x<<1|1].mx),max(a[x<<1].ans,a[x<<1|1].ans));
 19 }
 20 void upd2(L x,L k){
 21     a[x].tag2+=k; a[x].mx2+=k;
 22     if(a[x].l!=a[x].r) a[x].ans=max(max(a[x<<1].mx+a[x<<1|1].mx2,a[x<<1].mx2+a[x<<1|1].mx),max(a[x<<1].ans,a[x<<1|1].ans));
 23 }
 24 void pushdown(L x){
 25     if(a[x].tag!=0) upd(x<<1,a[x].tag),upd(x<<1|1,a[x].tag); a[x].tag=0;
 26     if(a[x].tag2!=0) upd2(x<<1,a[x].tag2),upd2(x<<1|1,a[x].tag2); a[x].tag2=0;
 27 }
 28 void pushup(L x){
 29     a[x].mx=max(a[x<<1].mx,a[x<<1|1].mx);
 30     a[x].mx2=max(a[x<<1].mx2,a[x<<1|1].mx2);
 31     a[x].ans=max(max(a[x<<1].mx+a[x<<1|1].mx2,a[x<<1].mx2+a[x<<1|1].mx),max(a[x<<1].ans,a[x<<1|1].ans));
 32 }
 33 void updata(L x,L l,L r,L k){
 34     if(l<=a[x].l&&a[x].r<=r) return upd(x,k);
 35     pushdown(x);
 36     if(l<=mid) updata(x<<1,l,r,k);
 37     if(mid<r) updata(x<<1|1,l,r,k);
 38     pushup(x);
 39 }
 40 void updata(L x,L k,L val){
 41     if(a[x].l==a[x].r){a[x].tag=0; a[x].mx=val; return;}
 42     pushdown(x);
 43     if(k<=mid) updata(x<<1,k,val);
 44     else updata(x<<1|1,k,val);
 45     pushup(x);
 46 }
 47 void updata2(L x,L l,L r,L k){
 48     if(l<=a[x].l&&a[x].r<=r) return upd2(x,k);
 49     pushdown(x);
 50     if(l<=mid) updata2(x<<1,l,r,k);
 51     if(mid<r) updata2(x<<1|1,l,r,k);
 52     pushup(x);
 53 }
 54 void updata2(L x,L k,L val){
 55     if(a[x].l==a[x].r){a[x].tag2=0; a[x].mx2=val; return;}
 56     pushdown(x);
 57     if(k<=mid) updata2(x<<1,k,val);
 58     else updata2(x<<1|1,k,val);
 59     pushup(x);
 60 }
 61 
 62 L cir[M]={0},vis[M]={0},n,m=0; stack<int> st;
 63 bool getcir(L x,L fa){
 64     if(vis[x]){
 65         for(L now=st.top();now!=x;st.pop(),now=st.top()){
 66             cir[++m]=now;
 67         }
 68         cir[++m]=x;
 69         return 1;
 70     }
 71     st.push(x); vis[x]=1;
 72     for(L i=head[x];i;i=e[i].next) if(e[i].u!=fa){
 73         if(getcir(e[i].u,x)) return 1;
 74     }
 75     st.pop();
 76     return 0;
 77 }
 78 
 79 void init(){
 80     scanf("%lld",&n);
 81     for(L i=1;i<=n;i++){
 82         L x,y,z; scanf("%lld%lld%lld",&x,&y,&z);
 83         add(x,y,z); add(y,x,z);
 84     }
 85 }
 86 
 87 L d[M]={0},s[M]={0},ans=0;
 88 L dfs(L x,L fa){
 89     L max1=0,max2=0;
 90     for(L i=head[x];i;i=e[i].next) if(e[i].u!=fa){
 91         L k=dfs(e[i].u,x)+e[i].v;
 92         if(k>max1) max2=max1,max1=k;
 93         else if(k>max2) max2=k;
 94     }
 95     ans=max(ans,max1+max2);
 96     return max1;
 97 }
 98 void getmax(){
 99     for(L x=1;x<=m;x++) cir[x+m]=cir[x]; 
100     cir[0]=cir[m]; cir[m*2+1]=cir[1];
101     for(L x=1;x<=m;x++){
102         L max1=0,max2=0;
103         for(L i=head[cir[x]];i;i=e[i].next)
104         if(e[i].u!=cir[x-1]&&e[i].u!=cir[x+1]){
105             L k=dfs(e[i].u,cir[x])+e[i].v;
106             if(k>max1) max2=max1,max1=k;
107             else if(k>max2) max2=k;
108         }
109         ans=max(ans,max1+max2);
110         d[x]=max1;
111     }
112     
113     for(L x=1;x<=2*m;x++){
114         L u=cir[x];
115         for(L i=head[u];i;i=e[i].next) 
116         if(e[i].u==cir[x+1]) s[x]=e[i].v;
117     }
118 }
119 
120 void work(){
121     L minn=0,S=0;
122     for(L i=1;i<=m;i++){
123         S+=s[i-1];
124         updata2(1,i,S+d[i]);
125         minn=max(minn,a[1].ans);
126         updata(1,i,d[i]-S);
127     }
128     for(L i=1;i<=m;i++){
129         updata(1,1,m,s[i]);
130         updata(1,i,-INF);
131         updata2(1,1,m,-s[i]);
132         updata2(1,i,-INF);
133         S-=s[i]; 
134         S+=s[i+m-1];
135         updata2(1,i,S+d[i]);
136         minn=min(minn,a[1].ans);
137         updata(1,i,d[i]-S);
138     }
139     ans=max(ans,minn);
140 }
141 
142 main(){
143     init();
144     getcir(1,0);
145     build(1,1,m);
146     getmax();
147     work();
148     double hh=ans; hh/=2;
149     printf("%.1lf\n",hh);
150 }

猜你喜欢

转载自www.cnblogs.com/xiefengze1/p/10382969.html