P2680 运输计划 树链剖分

  

在一颗有边权的树上有m条路径,清零一条边的边权使得m条路径的最大值最小。 输出这个最大值

显然 要遍历这m条路的最长路(如果最长路有多条随意遍历一条即可) 

因为树上距离不修改  那么用前缀和维护树上路径长度可以少一个log

然后遍历最长路的每一条边  ans=min(ans,max(最长路的长度-这条路的长度,不经过这条边的最长路长度)

所以现在需要维护的是不经过这条边的最长路长度

可以遍历m  将不在这条路径上的所有边 维护一个值(就是这条路径的长度) 用线段树维护最大值即可

#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define repp(i,a,b) for(int i=(a);i>=(b);--i)
#define ll long long
#define see(x) (cerr<<(#x)<<'='<<(x)<<endl)
#define inf 0x3f3f3f3f
#define CLR(A,v)  memset(A,v,sizeof A)
//////////////////////////////////
const int N=2e6+10;
int maxx[N<<2],col[N<<2],n,m,maxans[N],d[N],maxbian,flagx,flagy,val[N];
void build(int l,int r,int pos)
{
    if(l==r){maxx[pos]=0;return;}
    int m=(l+r)>>1;
    build(l,m,pos<<1);build(m+1,r,pos<<1|1);
    maxx[pos]=max(maxx[pos<<1],maxx[pos<<1|1]);
}
void down(int pos)
{
    if(!col[pos])return ;
    col[pos<<1]=max(col[pos<<1],col[pos]);
    col[pos<<1|1]=max(col[pos<<1|1],col[pos]);
    maxx[pos<<1]=max(maxx[pos<<1],col[pos]);
    maxx[pos<<1|1]=max(maxx[pos<<1|1],col[pos]);
    col[pos]=0;
}
void upsum(int L,int R,int v,int l,int r,int pos)
{
    if(L<=l&&r<=R){maxx[pos]=max(maxx[pos],v);col[pos]=max(col[pos],v);return ;}
    int m=(l+r)>>1;down(pos);
    if(L<=m)upsum(L,R,v,l,m,pos<<1);
    if(R>m)upsum(L,R,v,m+1,r,pos<<1|1);
    maxx[pos]=max(maxx[pos<<1],maxx[pos<<1|1]);
}
void qmax(int l,int r,int pos)
{
    if(l==r){maxans[l]=maxx[pos];return ;}
    int m=(l+r)>>1;down(pos);
    qmax(l,m,pos<<1);
    qmax(m+1,r,pos<<1|1);
}
int qmaxx(int x,int l,int r,int pos)
{
    if(l==r)return maxx[pos];
    int m=(l+r)>>1;down(pos);
    if(x<=m)return qmaxx(x,l,m,pos<<1);
    else return qmaxx(x,m+1,r,pos<<1|1);
}
int id[N],top[N],fa[N],dep[N],son[N],siz[N],pre[N],ncnt,pos,head[N];
struct Edge{int to,nex;}edge[N<<1];
void add(int a,int b){edge[++pos]=Edge{b,head[a]};head[a]=pos;}
void dfs1(int x,int f)
{
    fa[x]=f;dep[x]=dep[f]+1;siz[x]=1;son[x]=0;
    for(int i=head[x];i;i=edge[i].nex)
    {
        int v=edge[i].to;if(v==f)continue;
        dfs1(v,x);siz[x]+=siz[v];
        if(siz[son[x]]<siz[v])son[x]=v;
    }
}
void dfs2(int x,int topf)
{
    top[x]=topf;id[x]=++ncnt;pre[ncnt]=x;
    if(son[x])dfs2(son[x],topf);
    for(int i=head[x];i;i=edge[i].nex)
    {
        int v=edge[i].to;if(v==fa[x]||v==son[x])continue;
        dfs2(v,v);
    }
}
int u[N],v[N],w[N];
int Qdis(int x,int y)
{
    int ans=0;
    while(top[x]!=top[y])
    {
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        ans+=d[id[x]]-d[id[top[x]]-1];
        x=fa[top[x]];
    }
    if(dep[x]>dep[y])swap(x,y);
    ans+=d[id[y]]-d[id[x]];
    return ans;
}
struct node
{
    int x,y;
}s[N];
void UPsum(int x,int y,int v)
{
    int cnt=0;
    while(top[x]!=top[y])
    {
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        s[++cnt].x=id[top[x]],s[cnt].y=id[x];
        x=fa[top[x]];
    }
    if(dep[x]>dep[y])swap(x,y);
    s[++cnt].x=id[x]+1,s[cnt].y=id[y];
    sort(s+1,s+1+cnt,[](node a,node b){return a.x<b.x||a.x==b.x&&a.y<b.y;});
    if(s[1].x>1)upsum(1,s[1].x-1,v,1,n,1);
    if(s[cnt].y<n)upsum(s[cnt].y+1,n,v,1,n,1);
    rep(i,1,cnt-1)
    if(s[i].y+1<=s[i+1].x-1)upsum(s[i].y+1,s[i+1].x-1,v,1,n,1);
}
int getans(int x,int y)
{
    int ans=inf;
    if(x==y)return 0;
    while(x!=y)
    {
        if(dep[x]<dep[y])swap(x,y);
        ans=min(ans,max(maxbian-val[x],maxans[id[x]]));
        x=fa[x];
    }
    return ans;
}
int main()
{
    scanf("%d%d",&n,&m);
    rep(i,1,n-1)
    scanf("%d%d%d",&u[i],&v[i],&w[i]),add(u[i],v[i]),add(v[i],u[i]);
    dfs1(1,1);
    dfs2(1,1);
    build(1,n,1);
    rep(i,1,n-1)
    {
        if(dep[u[i]]<dep[v[i]])swap(u[i],v[i]);
        val[u[i]]=d[id[u[i]]]=w[i];
    }
    rep(i,1,n)
    d[i]+=d[i-1];
    while(m--)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        int temp=Qdis(x,y);
        if(temp>maxbian)maxbian=temp,flagx=x,flagy=y;
        UPsum(x,y,temp);
    }
    qmax(1,n,1);
    cout<<getans(flagx,flagy);
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/bxd123/p/11435290.html