可以使用树剖 nlog^2n 卡常后能过 就是码量有点大
详解在这里:https://www.luogu.org/blog/29354/solution-p2680
#include<bits/stdc++.h>
#define R register
using namespace std;
const int maxn=3e5+5;
char *P;
void QREAD()
{
static char buf[1<<25];P=&buf[0];
fread(buf,1,1<<25,stdin);
}
char get_char()
{
return *(P++);
}
void readint(int &x)
{
char ch=get_char();int f=1;x=0;
for(;;)
{
if(ch=='-')f=-1;
if(ch<'0'||ch>'9');
else break;
ch=get_char();
}
for(;;)
{
if(ch<'0'||ch>'9')break;
x*=10;x+=ch-'0';
ch=get_char();
}x*=f;
}
struct rmq
{
int t[maxn<<2],lazy[maxn<<2];
void pushup(int x){t[x]=max(t[x<<1],t[x<<1|1]);}
void pushdown(int x)
{
if(lazy[x]==0)return ;
lazy[x<<1]=max(lazy[x<<1],lazy[x]);
lazy[x<<1|1]=max(lazy[x<<1|1],lazy[x]);
t[x<<1]=max(t[x<<1],lazy[x<<1]);
t[x<<1|1]=max(t[x<<1|1],lazy[x<<1|1]);
}
void modify(int ql,int qr,int l,int r,int x,int val)
{
if(ql>qr)return;
if(ql<=l&&r<=qr)
{
t[x]=max(t[x],val);lazy[x]=max(lazy[x],val);
return ;
}
int m=(l+r)>>1;
pushdown(x);
if(ql<=m)modify(ql,qr,l,m,x<<1,val);
if(m<qr)modify(ql,qr,m+1,r,x<<1|1,val);
pushup(x);
}
int query(int ql,int qr,int l,int r,int x)
{
if(ql>qr)return -1;
if(ql<=l&&r<=qr)return t[x];
int m=(l+r)>>1,ret=-1;
pushdown(x);
if(ql<=m)ret=max(ret,query(ql,qr,l,m,x<<1));
if(m<qr)ret=max(ret,query(ql,qr,m+1,r,x<<1|1));
return ret;
}
}T;
struct segtreesum
{
int t[maxn<<2],lazy[maxn<<2];
void pushup(int x){t[x]=t[x<<1]+t[x<<1|1];}
void pushdown(int x,int ls,int rs)
{
if(lazy[x]==0)return ;
t[x<<1]+=lazy[x]*ls;t[x<<1|1]+=lazy[x]*rs;
lazy[x<<1]+=lazy[x];lazy[x<<1|1]+=lazy[x];
lazy[x]=0;
}
void modify(int ql,int qr,int l,int r,int x,int val)
{
if(ql>qr)return;
if(ql<=l&&r<=qr)
{
t[x]+=val;lazy[x]+=val;
return ;
}
int m=(l+r)>>1;
pushdown(x,m-l+1,r-m);
if(ql<=m)modify(ql,qr,l,m,x<<1,val);
if(m<qr)modify(ql,qr,m+1,r,x<<1|1,val);
pushup(x);
}
int query(int ql,int qr,int l,int r,int x)
{
if(ql>qr)return 0;
if(ql<=l&&r<=qr)return t[x];
int m=(l+r)>>1,ret=0;
pushdown(x,m-l+1,r-m);
if(ql<=m)ret+=query(ql,qr,l,m,x<<1);
if(m<qr)ret+=query(ql,qr,m+1,r,x<<1|1);
return ret;
}
}t;
struct Edge
{
int to,val,nxt;
}edge[maxn<<2];int EC;
int head[maxn];
void add(int a,int b,int t)
{
++EC;
edge[EC].nxt=head[a];edge[EC].to=b;edge[EC].val=t;head[a]=EC;
}
int n,m;
void read()
{
readint(n);readint(m);
for(R int i=1; i<n; i++)
{
R int a,b,t;
readint(a);readint(b);readint(t);
add(a,b,t);
add(b,a,t);
}
}
int mson[maxn],dep[maxn],sz[maxn],fa[maxn];
void dfs1(int x,int f)
{
dep[x]=dep[f]+1;sz[x]=1;fa[x]=f;
for(R int i=head[x];i!=0; i=edge[i].nxt)
{
int to=edge[i].to;
if(to==f)continue;
dfs1(to,x);
if(mson[x]==0)mson[x]=to;else if(sz[mson[x]]<sz[to])mson[x]=to;
sz[x]+=sz[to];
}
}
int id[maxn],cnt=0,top[maxn];
void dfs2(int x,int tp)
{
++cnt;id[x]=cnt;top[x]=tp;
if(!mson[x])return ;
dfs2(mson[x],tp);
for(R int i=head[x]; i!=0; i=edge[i].nxt)
{
int to=edge[i].to;
if(to==fa[x]||to==mson[x])continue;
dfs2(to,to);
}
}
int elen[maxn];
void count(int x,int tl)
{
//和普通点权不同的是,对于一颗树来说,每一个点的点权被定义为他的父亲到他的边权
//边转点
elen[id[x]]=tl;
if(x!=1)
{
t.modify(id[x],id[x],1,n,1,tl);
}
for(R int i=head[x];i!=0;i=edge[i].nxt)
{
int to=edge[i].to,val=edge[i].val;
if(to==fa[x])continue;
count(to,val);
}
}
int ask(int u,int v)
{
R int ret=0;
while(top[u]!=top[v])
{
if(dep[top[u]]>dep[top[v]])swap(u,v);
ret+=t.query(id[top[v]],id[v],1,n,1);
v=fa[top[v]];
}
if(dep[u]>dep[v])swap(u,v);
ret+=t.query(id[u]+1,id[v],1,n,1);
return ret;
}
int ans,ori;
void go(int u,int v)
{
while(top[u]!=top[v])
{
if(dep[top[u]]>dep[top[v]])swap(u,v);
ans=min(ans,max(ori-elen[id[v]],T.query(id[v],id[v],1,n,1)));
v=fa[v];
}
if(dep[u]>dep[v])swap(u,v);
while(u!=v)
{
ans=min(ans,max(ori-elen[id[v]],T.query(id[v],id[v],1,n,1)));
v=fa[v];
}
}
vector<pair<int,int> >chain[maxn];int csz;
void makechain(int u,int v)
{
while(top[u]!=top[v])
{
if(dep[top[u]]>dep[top[v]])swap(u,v);
int st=id[top[v]],ed=id[v];
if(st<=ed)chain[csz].push_back(make_pair(st,ed));
v=fa[top[v]];
}
if(dep[u]>dep[v])swap(u,v);
int st=id[u]+1,ed=id[v];if(st<=ed)chain[csz].push_back(make_pair(st,ed));
csz++;
}
vector<pair<int,int> >query;
vector<int>qans;
int mem;
void prepare()
{
dfs1(1,1);
dfs2(1,1);
count(1,1);
}
void solve()
{
prepare();
ans=-1;
for(R int i=1;i<=m;i++)
{
R int u,v;readint(u);readint(v);
query.push_back(make_pair(u,v));
makechain(u,v);
int len=ask(u,v);qans.push_back(len);
if(len>ans)ans=len,mem=i-1;
}
ori=ans;
for(R int i=0;i<csz;i++)
{
sort(chain[i].begin(),chain[i].end());
int st=1;
for(int j=0;j<(int)chain[i].size();j++)
{
T.modify(st,chain[i][j].first-1,1,n,1,qans[i]);
st=chain[i][j].second+1;
}
T.modify(st,n,1,n,1,qans[i]);
}
go(query[mem].first,query[mem].second);
printf("%d\n",ans);
}
int main()
{
QREAD();
read();
solve();
return 0;
}
或者使用树上差分
check函数:check(t)
设路径长度超过t的路径的总数为s,如果一条边被经过恰好s次,且maxlen(最长路径长度)-edgelen<=t 那么就可行
(卡常好烦)
#include<bits/stdc++.h>
#define R register
using namespace std;
const int maxn=3e5+5;
char *P;
void qread(){static char buf[1<<24];fread(buf,1,1<<24,stdin);P=&buf[0];}
char get_char(){return *P++;}
void readint(int &x)
{
int f=1;x=0;char ch;
for(;;)
{
ch=getchar();
if(ch=='-'){f=-1;ch=getchar();break;}
if(ch<'0'||ch>'9');else break;
}
for(;;)
{
if(ch<'0'||ch>'9')break;
x*=10;x+=ch-'0';ch=getchar();
}
x*=f;
}
int n,m;
struct EDGE
{
int to,val,nxt;
}edge[maxn<<3];int ec;
int head[maxn];
void addedge(int u,int v,int l)
{
++ec;
edge[ec].nxt=head[u];edge[ec].val=l;edge[ec].to=v;
head[u]=ec;
}
//--------------------lca
int fa[maxn];
int Log[maxn<<3];
int st[21][maxn<<3];
int ord[maxn<<2],ptr,in[maxn],dep[maxn];
void dfs(int x,int f)
{
++ptr;ord[ptr]=x;in[x]=ptr;
fa[x]=f;dep[x]=dep[f]+1;
for(R int i=head[x];i;i=edge[i].nxt)
{
int to=edge[i].to;
if(to==f)continue;
dfs(to,x);
++ptr;ord[ptr]=x;
}
}
int query(int x,int y)
{
int l=min(x,y),r=max(x,y);
int len=r-l+1,lg=Log[len];
int a=st[lg][l],b=st[lg][r-(1<<lg)+1];
return dep[a]<dep[b]?a:b;
}
int Lca(int u,int v)
{
return query(in[u],in[v]);
}
void bld()
{
for(int i=1;i<=ptr;i++)
{
st[0][i]=ord[i];
}
for(R int j=1;j<=19;j++)
{
for(R int i=1;i+(1<<j)<=ptr;i++)
{
int a=st[j-1][i],b=st[j-1][i+(1<<(j-1))];
st[j][i]=dep[a]<dep[b]?a:b;
}
}
}
//---------------------------------------------
int elen[maxn],dis[maxn];
void getlen(int x,int el)
{
elen[x]=el;
for(R int i=head[x];i;i=edge[i].nxt)
{
int to=edge[i].to,len=edge[i].val;
if(to==fa[x])continue;
dis[to]=dis[x]+len;getlen(to,len);
}
}
int len[maxn],mxl,mxe;
int q1[maxn],q2[maxn],lca[maxn];
void prepare()
{
for(R int i=1;i<=m;i++)
{
len[i]=-2*dis[lca[i]]+dis[q1[i]]+dis[q2[i]];
mxl=max(mxl,len[i]);
}
}
int ROOT;
int buc[maxn],cnt[maxn];
void sum(int x)
{
cnt[x]=buc[x];
for(R int i=head[x];i;i=edge[i].nxt)
{
int to=edge[i].to;
if(to==fa[x])continue;
sum(to);
cnt[x]+=cnt[to];
}
}
int check(int t)
{
memset(buc,0,sizeof(buc));
int mxlen=-1;
int cc=0;
for(R int i=1;i<=m;i++)
{
if(len[i]>t)
{
buc[q1[i]]++;buc[q2[i]]++;buc[lca[i]]-=2;
mxlen=max(mxlen,len[i]);
cc++;
}
}
sum(ROOT);
int f=0;
for(R int i=1;i<=n;i++)
{
if(cnt[i]==cc)
{
if(mxlen-elen[i]<=t)
{
f=1;break;
}
}
}
return f;
}
void solve()
{
int l=mxl-mxe,r=mxl,ans=0;
while(l<=r)
{
int m=l+r>>1;
if(check(m))
{
ans=m;r=m-1;
}
else l=m+1;
}
printf("%d\n",ans);
}
int main()
{
// freopen("transport.in","r",stdin);freopen("transport.out","w",stdout);
srand(time(0));
readint(n);readint(m);
ROOT=rand()%n+1;
for(int i=1;i<n;i++)
{
int a,b,t;readint(a);readint(b);readint(t);
addedge(a,b,t);
addedge(b,a,t);
mxe=max(mxe,t);
}
dfs(ROOT,ROOT);getlen(ROOT,0);bld();
for(int i=0;i<=20;i++)
{
Log[1<<i]=i;
}
for(R int i=1,t=0;i<=maxn<<1;i++)
{
if(Log[i])
{
t=Log[i];continue;
}
Log[i]=t;
}
for(R int i=1;i<=m;i++)
{
readint(q1[i]);readint(q2[i]);
lca[i]=Lca(q1[i],q2[i]);
}
prepare();
solve();
return 0;
}