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

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

数据范围:n105,边权109

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

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

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

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

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

那么,对于环上两点(i,j),由i为根子树,j为根子树,还有i至j的链构成的树的直径为Di+DjSi+Sj

移项后有(DiSi)+(Dj+Sj)

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

复制代码
  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 }
复制代码

 

posted @   AlphaInf  阅读(147)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
点击右上角即可分享
微信分享提示