NOIP2015最后一题,实际上不难,艹起来比D1T3(斗地主)舒服多了
听说要卡常,求LCA就从倍增换成了tarjan,但不知道noip的老爷机过得了不,反正bzoj我感觉7860ms还不是很慢
然后大概思路很简单,先二分答案,检验的时候差分,在对所有比枚举值大的路径lca-=2,s++,v++然后dfs找都经过的边就可以了
程序见下:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<set>
#include<map>
#include<queue>
#include<algorithm>
#include<vector>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<stack>
#define INF 2100000000
#define ll long long
#define clr(x) memset(x,0,sizeof(x))
#define maxclr(x) memset(x,127,sizeof(x))
#pragma comment(linker,"/STACK:102400000,1024000")
using namespace std;
inline int read()
{
char c='q';
int ret=0;
while(!(c>='0'&&c<='9'))
c=getchar();
while(c>='0'&&c<='9')
{
ret=(c-'0')+(ret<<1)+(ret<<3);
c=getchar();
}
return ret;
}
#define M 300005
int first[M],lext[M<<1],to[M<<1],d[M<<1],t;
int fa[M],ufa[M],lca[M],lcad[M],vis[M],dis[M];
int first2[M],next2[M<<1],to2[M<<1],num[M<<1],t2;
int S[M],V[M],cf[M];
int n,m,mx,sum;
void addedge(int s,int v,int val)
{
lext[++t]=first[s];
first[s]=t;
to[t]=v;
d[t]=val;
}
void addedge2(int s,int v,int fig)
{
next2[++t2]=first2[s];
first2[s]=t2;
to2[t2]=v;
num[t2]=fig;
}
int get_fa(int x)
{
return x==ufa[x]?x:ufa[x]=get_fa(ufa[x]);
}
inline void tarjan(int x,int w)
{
dis[x]=w;
vis[x]=1;
ufa[x]=x;
for(int i=first[x];i;i=lext[i])
{
int v=to[i];
if(v==fa[x])continue;
fa[v]=x;
tarjan(v,w+d[i]);
ufa[v]=x;
}
for(int i=first2[x];i;i=next2[i])
{
int v=to2[i],p=num[i];
if(!vis[v])continue;
lca[p]=get_fa(v);
lcad[p]=dis[x]+dis[v]-dis[lca[p]]*2;
mx=max(mx,lcad[p]);
}
}
inline void dfs(int x)
{
for(int i=first[x];i;i=lext[i])
{
int v=to[i];
if(v==fa[x])continue;
dfs(v);
if(cf[v]==sum)
mx=max(mx,d[i]);
cf[x]+=cf[v];
}
}
bool check(int x)
{
sum=0;
int maxx=0;
clr(cf);
for(int i=1;i<=m;i++)
if(lcad[i]>x)
{
sum++;
cf[S[i]]++;
cf[V[i]]++;
cf[lca[i]]-=2;
maxx=max(maxx,lcad[i]);
}
if(sum==0)return 1;
mx=0;
dfs(1);
return maxx-mx<=x;
}
int main()
{
freopen("transport.in","r",stdin);
freopen("transport.out","w",stdout);
n=read();m=read();
for(int i=1;i<n;i++)
{
int a=read(),b=read(),c=read();
addedge(a,b,c);
addedge(b,a,c);
}
for(int i=1;i<=m;i++)
{
int a=read(),b=read();
addedge2(a,b,i);
addedge2(b,a,i);
S[i]=a;
V[i]=b;
}
tarjan(1,0);
int l=0,r=mx+1,mid;
while(r>l)
{
mid=(l+r)>>1;
if(check(mid))r=mid;
else l=mid+1;
}
printf("%d",l);
return 0;
}
大概就是这个样子,如果有什么问题,或错误,请在评论区提出,谢谢。