【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 }