版权声明:我这种蒟蒻的文章,真正的大佬一般看不上的_(:з」∠)_ https://blog.csdn.net/Paulliant/article/details/82864697
题意
https://www.luogu.org/problemnew/show/P2680
思路
最大路径最短,二分吧。。。然后就二分了,考试时
分,常数太大,边界设的太大。
二分的边界如果设的小,能大大减小常数,对于这道题,最长时间肯定不会长过最长路径的值,短过最长路径减整棵树上的最长边。这样算一下顶多二分
次,血赚。
二分的
也比较清晰,对于一个给定的最短路最大值
,将
条路径中长度超过
的都标记掉,考虑清掉一条被所有路径覆盖的边的权值,如果存在清掉某条边的权值,能使最长不合法的路径长度不超过
,那么这个
合法,尝试更小的
。
但是
的常数很大,导致在比较慢的测评机上
,如果把
标记差分改成跳重链标记,看上去像多了一个
,实际上少了一个大常数,记住跳重链常数很小。
仔细观察,如果清边不删在最长的给定路径上的话,就没什么意义了,由此想到“抽出”最长路径,然后将子树挂在下面,这也是树的一个很好的结构。
如果清除了某条边的权值,不难发现只要对这条边左边子树的最长路、右边子树的最长路、清完边后拉出最长路的长度取
即可,所以在拉出路径后维护一个前缀、后缀最大值。
代码
二分答案+差分
#include<bits/stdc++.h>
#define FOR(i,x,y) for(int i=(x),i##END=(y);i<=i##END;++i)
#define DOR(i,x,y) for(int i=(x),i##END=(y);i>=i##END;--i)
typedef long long LL;
using namespace std;
const int N=3e5+3;
template<const int maxn,const int maxm>struct Linked_list
{
int head[maxn],to[maxm],cost[maxm],nxt[maxm],tot;
void clear(){memset(head,-1,sizeof(head));tot=0;}
void add(int u,int v,int w){to[++tot]=v,cost[tot]=w,nxt[tot]=head[u],head[u]=tot;}
#define EOR(i,G,u) for(int i=G.head[u];~i;i=G.nxt[i])
};
Linked_list<N,N<<1>G;
int dep[N],fa[N],sz[N],son[N],top[N],ed[N],dis[N],dfn[N],ord,dif[N];
int X[N],Y[N],lca[N],Pt[N],n,m,maxer,maxed;
void dfs(int u,int f,int d,int D)
{
dep[u]=d,fa[u]=f,sz[u]=1,son[u]=0,dis[u]=D;
EOR(i,G,u)
{
int v=G.to[i],w=G.cost[i];
if(v==f)continue;
ed[v]=w;
dfs(v,u,d+1,D+w);
sz[u]+=sz[v];
if(sz[v]>sz[son[u]])son[u]=v;
}
}
void make_path(int u,int f,int tp)
{
dfn[u]=++ord,top[u]=tp;
if(son[u])make_path(son[u],u,tp);
EOR(i,G,u)
{
int v=G.to[i];
if(v==f||v==son[u])continue;
make_path(v,u,v);
}
}
int LCA(int x,int y)
{
while(top[x]!=top[y])
{
if(dep[top[x]]>dep[top[y]])x=fa[top[x]];
else y=fa[top[y]];
}
return dep[x]<dep[y]?x:y;
}
void update(int x,int y)
{
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]])swap(x,y);
dif[dfn[top[x]]]++,dif[dfn[x]+1]--;
x=fa[top[x]];
}
if(dep[x]<dep[y])swap(x,y);
dif[dfn[y]+1]++,dif[dfn[x]+1]--;
}
bool check(int k)
{
int cnt=0,maxcut=0;
memset(dif,0,sizeof(dif));
FOR(i,1,m)if(Pt[i]>k)
{
cnt++;
update(X[i],Y[i]);
}
FOR(i,1,n)dif[i]+=dif[i-1];
FOR(i,1,n)if(dif[dfn[i]]==cnt)
maxcut=max(maxcut,ed[i]);
return maxer-maxcut<=k;
}
int main()
{
G.clear();
scanf("%d%d",&n,&m);
FOR(i,1,n-1)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
G.add(u,v,w);
G.add(v,u,w);
maxed=max(maxed,w);
}
dfs(1,0,1,0);
make_path(1,0,1);
FOR(i,1,m)
{
scanf("%d%d",&X[i],&Y[i]);
lca[i]=LCA(X[i],Y[i]);
Pt[i]=dis[X[i]]+dis[Y[i]]-2*dis[lca[i]];
maxer=max(maxer,Pt[i]);
}
int l=maxer-maxed,r=maxer,mid;
while(l<r)
{
mid=l+r>>1;
if(check(mid))
r=mid;
else l=mid+1;
}
printf("%d\n",l);
return 0;
}
抽路+前缀最大值
#include<bits/stdc++.h>
#define FOR(i,x,y) for(int i=(x),i##END=(y);i<=i##END;++i)
#define DOR(i,x,y) for(int i=(x),i##END=(y);i>=i##END;--i)
typedef long long LL;
using namespace std;
const int N=3e5+3;
template<const int maxn,const int maxm>struct Linked_list
{
int head[maxn],to[maxm],cost[maxm],nxt[maxm],tot;
void clear(){memset(head,-1,sizeof(head));tot=0;}
void add(int u,int v,int w){to[++tot]=v,cost[tot]=w,nxt[tot]=head[u],head[u]=tot;}
#define EOR(i,G,u) for(int i=G.head[u];~i;i=G.nxt[i])
};
Linked_list<N,N<<1>G;
int dep[N],fa[N],sz[N],son[N],top[N],dis[N];
int X[N],Y[N],Ds[N],n,m,maxer=-1;
int Pt[N],ed[N],ID[N],pref[N],suff[N],p,len,Fa[N];
void dfs(int u,int f,int d,int D)
{
dep[u]=d,fa[u]=f,sz[u]=1,son[u]=0,dis[u]=D;
EOR(i,G,u)
{
int v=G.to[i],w=G.cost[i];
if(v==f)continue;
dfs(v,u,d+1,D+w);
sz[u]+=sz[v];
if(sz[v]>sz[son[u]])son[u]=v;
}
}
void make_path(int u,int f,int tp)
{
top[u]=tp;
if(son[u])make_path(son[u],u,tp);
EOR(i,G,u)
{
int v=G.to[i];
if(v==f||v==son[u])continue;
make_path(v,u,v);
}
}
int LCA(int x,int y)
{
while(top[x]!=top[y])
{
if(dep[top[x]]>dep[top[y]])x=fa[top[x]];
else y=fa[top[y]];
}
return dep[x]<dep[y]?x:y;
}
void dfs_mark(int u,int f)
{
EOR(i,G,u)
{
int v=G.to[i];
if(v==f)continue;
if(Fa[v])continue;
Fa[v]=Fa[u];
dfs_mark(v,u);
}
}
bool Draw(int u,int f,int To)
{
if(u==To)
{
Pt[++len]=u;
return 1;
}
EOR(i,G,u)
{
int v=G.to[i],w=G.cost[i];
if(v==f)continue;
Pt[++len]=u,ed[len]=w;
if(Draw(v,u,To))return 1;
len--;
}
return 0;
}
int main()
{
G.clear();
scanf("%d%d",&n,&m);
FOR(i,1,n-1)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
G.add(u,v,w);
G.add(v,u,w);
}
dfs(1,0,1,0);
make_path(1,0,1);
FOR(i,1,m)
{
scanf("%d%d",&X[i],&Y[i]);
Ds[i]=dis[X[i]]+dis[Y[i]]-2*dis[LCA(X[i],Y[i])];
if(Ds[i]>maxer)
{
maxer=Ds[i];
p=i;
}
}
Draw(X[p],0,Y[p]);
FOR(i,1,len)
{
Fa[Pt[i]]=Pt[i];
ID[Pt[i]]=i;
}
FOR(i,1,len)dfs_mark(Pt[i],0);
int ans=maxer;
FOR(i,1,m)if(i!=p)
{
if(ID[Fa[X[i]]]>ID[Fa[Y[i]]])
swap(X[i],Y[i]);
suff[ID[Fa[X[i]]]]=max(suff[ID[Fa[X[i]]]],Ds[i]);
pref[ID[Fa[Y[i]]]]=max(pref[ID[Fa[Y[i]]]],Ds[i]);
}
FOR(i,2,len)pref[i]=max(pref[i],pref[i-1]);
DOR(i,len-1,1)suff[i]=max(suff[i],suff[i+1]);
FOR(i,1,len-1)ans=min(ans,max(maxer-ed[i],max(pref[i],suff[i+1])));
printf("%d\n",ans);
return 0;
}