• 【树形结构】51nod 1766 树上的最远点对


    题目内容

    (n)个点被(n−1)条边连接成了一颗树,边有权值(w_i)。有(q)个询问,给出([a,b])([c,d])两个区间,表示点的标号请你求出两个区间内各选一点之间的最大距离,即你需要求出

    [max { ext{dis}(i,j)vert iin[a,b],jin [c,d] } ]

    数据范围

    (1≤n,q≤10^5,1≤w_i≤10^4)

    思路

    好像其实是很好写的一道题(虽然考场我写的暴力orz)

    先想树的直径的合并性质:

    (<a,b>)(<c,d>)分别为原来两棵树的直径,那么合并后的新直径必定为(<a,b>)(<c,d>)(<a,c>)(<a,d>)(<b,c>)(<b,d>)中的最大值。

    那么对于本题的路径合并也是类似,可以通过反证法证明。

    假设原来的直径为(<a,b>),设合并之后的直径不是以(a,b)中的为端点而是(<c,d>),那么可以得出( ext{dis}(b,d))( ext{dis}(a,d))均要小于( ext{dis}(c,d))。可以看出(<e,d>)是公共的,那么可以得出( ext{dis}(b,e))( ext{dis}(a,e))均小于( ext{dis}(c,e)),那么你一开始求直径的时候就会选择(<b,c>)(<a,c>)其中一条,而不是(<a,b>)

    那么关于这个性质我们就可以开一个线段树,内存最大路径的端点下标,通过以上的性质合并。需要注意的是倍增求( ext{LCA})常数太大会导致超时,所以可以选择树剖或( ext{ST})表求( ext{LCA})

    然后这里提供一种重载运算符的写法,感觉比直接写好多if少很多(但是本人习惯扩行qwq看起来和正常写法差不多),然后本人过于蒻所以不会( ext{ST})表求( ext{LCA})所以写的树剖。

    代码

    #include <bits/stdc++.h>
    #define lson (rt<<1)
    #define rson (rt<<1|1)
    using namespace std;
    const int maxn=1e5+10;
    int n,m;
    
    struct Edge{
        int from,to,w,nxt;
    }e[maxn<<1];
    
    inline int read(){
        int x=0,fopt=1;
        char ch=getchar();
        while(!isdigit(ch)){
            if(ch=='-')fopt=-1;
            ch=getchar();
        }
        while(isdigit(ch)){
            x=(x<<3)+(x<<1)+ch-48;
            ch=getchar();
        }
        return x*fopt;
    }
    
    int head[maxn],cnt;
    inline void add(int u,int v,int w){
        e[++cnt].from=u;
        e[cnt].to=v;
        e[cnt].w=w;
        e[cnt].nxt=head[u];
        head[u]=cnt;
    }
    
    int fa[maxn],dep[maxn],siz[maxn],dis[maxn],son[maxn];
    void dfs1(int u){
        dep[u]=dep[fa[u]]+1;siz[u]=1;
        for(register int i=head[u];i;i=e[i].nxt){
            int v=e[i].to;
            if(v==fa[u])continue;
            fa[v]=u;
            dis[v]=dis[u]+e[i].w;
            dfs1(v);
            siz[u]+=siz[v];
            if(!son[u]||siz[v]>siz[son[u]])son[u]=v;
        }
    }
    
    int top[maxn];
    void dfs2(int u,int t){
        top[u]=t;
        for(register int i=head[u];i;i=e[i].nxt){
            int v=e[i].to;
            if(v==fa[u])continue;
            dfs2(v,v==son[u]?t:v);
        }
    }
    
    inline int lca(int u,int v){
        while(top[u]!=top[v]){
            if(dep[top[u]]<dep[top[v]])swap(u,v);
            u=fa[top[u]];
        }
        return dep[u]<dep[v]?u:v;
    }
    
    inline int Getdis(int u,int v){
        return dis[u]+dis[v]-2*dis[lca(u,v)];
    }
    
    struct Node{
        int l,r;
        friend inline Node operator +(const Node& A,const Node& B){
            int p[4]={A.l,A.r,B.l,B.r};
            int Max=-1;
            Node res;
            for(int i=0;i<4;i++)
                for(int j=i+1;j<4;j++){
                    int w=Getdis(p[i],p[j]);
                    if(w>Max){
                        Max=w;
                        res=(Node){p[i],p[j]};
                    }
                }
            return res;
        }
    }tree[maxn<<2];
    
    inline void pushup(int rt){
        tree[rt]=tree[lson]+tree[rson];
    }
    
    inline void Build(int rt,int l,int r){
        if(l==r){
            tree[rt].l=tree[rt].r=l;
            return;
        }
        int mid=(l+r)>>1;
        Build(lson,l,mid);
        Build(rson,mid+1,r);
        pushup(rt);
    }
    
    inline Node query(int rt,int l,int r,int s,int t){
        if(s<=l&&t>=r)
            return tree[rt];
        int mid=(l+r)>>1;
        if(t<=mid)return query(lson,l,mid,s,t);
        else if(s>=mid+1)return query(rson,mid+1,r,s,t);
        else return query(lson,l,mid,s,mid)+query(rson,mid+1,r,mid+1,t);
    }
    
    inline int Mymax(int a,int b,int c,int d){
        return max(a,max(b,max(c,d)));
    }
    
    int main(){
        freopen("D.in","r",stdin);
        freopen("D.out","w",stdout);
        n=read();
        for(register int i=1;i<n;i++){
            int x=read(),y=read(),z=read();
            add(x,y,z);
            add(y,x,z);
        }
        
        dfs1(1);
        dfs2(1,1);
        Build(1,1,n);
        
        m=read();
        while(m--){
            int a=read(),b=read(),c=read(),d=read();
            Node x=query(1,1,n,a,b);
            Node y=query(1,1,n,c,d);
            int ans=Mymax(Getdis(x.l,y.l),Getdis(x.l,y.r),Getdis(x.r,y.l),Getdis(x.r,y.r));
            printf("%d
    ",ans);
        }
        return 0;
    }
    
  • 相关阅读:
    关于sifari兼容性的一个问题
    HTML标签的应用(新手)
    HTML标签的应用(新手)
    未完成的开锁动画演示
    HTML标签的应用(新手)
    HTML新手向
    C++
    STL之set
    C++输入输出
    提升一下逼格
  • 原文地址:https://www.cnblogs.com/Midoria7/p/13496774.html
Copyright © 2020-2023  润新知