• 树上路径


    题目意思:给出一棵树,求出最小的k,使得,且在树中存在路径p,使得k>=S且k<=E。(k为路径p上的边的权值和)

    数据范围:(nle1e5,Sle Ele 1e9)

    Solution:

    这里提供两种思路,第一种是二分k,点分治求出距离,时间复杂度(O(n\,log\,n\,log\,(E-S))),比较容易写挂,且容易TLE

    第二种是对于每一个点,预处理出离他最近的不同子树的且满足距离之和大于S的点,然后即可暴力更新答案

    这里给出第二种写法的代码(第一种写T了QAQ)

    Code:

    #pragma GCC optimize(3)
    #include<bits/stdc++.h>
    #define inf 2147483647
    using namespace std;
    const int N=2e6+5;
    int rt,cnt,szt,head[N],sz[N],mx[N],go[N];
    int n,L,R,tot,dis[N],vis[N],ans=inf;
    struct Edge{int nxt,to,val;}edge[N<<1];
    struct pos{int dis,be;}p[N];
    inline bool cmp(pos a,pos b){return a.dis<b.dis;}
    void ins(int x,int y,int z){
        edge[++cnt].nxt=head[x];
        edge[cnt].to=y;edge[cnt].val=z;
        head[x]=cnt;
    }
    void getrt(int x,int fa){
        mx[x]=0,sz[x]=1;
        for(int i=head[x];i;i=edge[i].nxt){
            int y=edge[i].to;
            if(vis[y]||y==fa) continue;
            getrt(y,x);sz[x]+=sz[y];
            mx[x]=max(mx[x],sz[y]);
        }
        mx[x]=max(mx[x],szt-sz[x]);
        if(mx[x]<mx[rt]) rt=x;
    }
    void getdis(int x,int fa,int d,int rtt){
        p[++tot].dis=d;p[tot].be=rtt;
        for(int i=head[x];i;i=edge[i].nxt){
            int y=edge[i].to;
            if(vis[y]||y==fa) continue;
            getdis(y,x,d+edge[i].val,rtt);
        }
    }
    int find(int l,int r,int x){
        while(l<r){
            int mid=(l+r)>>1;
            if(x+p[mid].dis<L) l=mid+1;
            else r=mid;
        }return l;
    }
    void divide(int x){
        vis[x]=1;tot=0;
        for(int i=head[x];i;i=edge[i].nxt){
            int y=edge[i].to;
            if(vis[y]) continue;
            getdis(y,x,edge[i].val,y);
        }
        sort(p+1,p+tot+1,cmp);
        for(int i=1;i<=tot;i++)
            if(p[i].dis>=L&&p[i].dis<=R) ans=min(ans,p[i].dis);
        for(int i=tot;i>=1;i--){
            if(p[i].be!=p[i+1].be) go[i]=i+1;
            else go[i]=go[i+1];
        }p[tot+1].dis=0;
        for(int i=1;i<=tot;i++){
            int u=find(i+1,tot,p[i].dis);
            if(p[u].be==p[i].be) u=go[u];
            int now=p[u].dis+p[i].dis;
            if(now>=L&&now<=R) ans=min(ans,now);
            go[i]=0;
        }
        for(int i=head[x];i;i=edge[i].nxt){
            int y=edge[i].to;
            if(vis[y]) continue;
            szt=sz[y];rt=0;getrt(y,x);
            divide(rt);
        }
    }
    int read(){
        int x=0,f=1;char ch=getchar();
        while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
        while(isdigit(ch)){x=x*10+ch-48;ch=getchar();}
        return x*f;
    }
    int main(){
        n=read(),L=read(),R=read();
        if(R<L) swap(L,R);
        for(int i=1;i<n;i++){
            int x=read(),y=read(),z=read();
            ins(x,y,z);ins(y,x,z);
        }
        mx[rt]=inf;szt=n;getrt(1,0);
        divide(rt);printf("%d
    ",ans==inf?-1:ans);
        return 0;
    }
    
  • 相关阅读:
    Git合并
    Git对象
    Git储藏和引用日志
    小小c#算法题 4 子数组最大和
    小小c#算法题 2 求素数
    小小c#算法题 5 插入排序
    小小c#算法题 1 找出数组中满足条件的两个数
    [转] WPF – Editing Mode with Save and Cancel Capability
    小小c#算法题 0 单循环冒泡排序
    小小c#算法题 3 字符串语句反转
  • 原文地址:https://www.cnblogs.com/NLDQY/p/10822056.html
Copyright © 2020-2023  润新知