• csu 1798(树上最远点对,线段树+lca)


    1798: 小Z的城市

    Time Limit: 5 Sec  Memory Limit: 128 MB
    Submit: 60  Solved: 16
    [Submit][Status][Web Board]

    Description

    小Z身为A国的君王,A国的所有城市都归小A所有,A国中从任意一个城市出发都能到达其他任意一个城市,每两个直接相邻的城市xi , yi之间都有一条已知长度的路径相连。A国共有n个城市(编号为1~n),被n-1条无向边相连。小Y和小X的开国功臣,但是小X擅文,小Y好武,所以他们关系很差,现在小Z想在区间[l ,r]的城市中选择两个奖赏这两位开国功臣一人一个城市,彼此厌恶的小X和小Y想让聪明的你飞到A国帮助他们做出选择可以距离彼此更远。

    (也就是说最后小X会选择城市idx(l<=idx<=r) , 小Y会选择城市idy(l<=idy<=r) , 保证idx!=idy 而且idx距离idy尽可能远)。

    Input

    多组数据

    每组数据第一行两个正整数n和q 表示A国有n个城市,q次询问 ( 2<=n <=100000 , q<=100000 )

    接下来n-1行,每行输入3个正整数xi , yi , di 表示城市xi与yi被一条长度为di的路径相连

    (1<=xi , yi<=n , di<=100)

    接下来q个询问,每次询问输入一行li和ri,对于每次询问希望在li和ri区间选择两个城市分给小X和小Y,使他们距离最大 (1<=li < ri<=n)

    所有数据保证Σn <=500000

    Output

    每次询问输出一个使小X和小Y距离的最大值

    Sample Input

    5 1
    1 2 1
    2 3 2
    1 4 3
    4 5 4
    2 5
    

    Sample Output

    10



    题解:线段树+lca .. 首先要知道一个这样的东西,假如一棵子树 A和另外一棵子树 B合并成 C,那么C 里面的最远点对是原来的A树里面最远点对和B树里面的最远点对这四个点中间的 2 个.所以知道了这个特性

    所有的点下面的子树的最远点对就可以利用线段树进行维护了,树上最远的两个点之间的距离是 dis[u]+dis[v]-2*dis[lca(u,v)]
    #include <bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef vector<int> vi;
    const int N = 200005;
    const int DEG = 25;
    int n,q;
    struct Edge
    {
        int v,w,next;
    } edge[N];
    int head[N],tot,cost[N];
    void addEdge(int u,int v,int w)
    {
        edge[tot].v = v,edge[tot].w = w,edge[tot].next = head[u],head[u] = tot++;
    }
    void init()
    {
        memset(head,-1,sizeof(head));
        tot = 0;
    }
    /************* lca  调用 dfs(1,0,0) 以及 getanc() ***************/
    int anc[N][DEG],dep[N];
    void dfs(int u,int fa,int d,int w)
    {
        dep[u]=d;
        anc[u][0]=fa;
        cost[u] = w;
        for (int i=head[u]; i!=-1; i=edge[i].next)
            if (edge[i].v!=fa) dfs(edge[i].v,u,d+1,w+edge[i].w);
    }
    
    void getanc()
    {
        for (int i=1; i<DEG; i++)
            for (int j=1; j<=n; j++)
                anc[j][i]=anc[anc[j][i-1]][i-1];
    }
    
    int swim(int u,int H)
    {
        int i=0;
        while (H)
        {
            if (H&1) u=anc[u][i];
            i++;
            H>>=1;
        }
        return u;
    }
    
    int lca(int u,int v)
    {
        if (dep[u]<dep[v]) swap(u,v);
        u=swim(u,dep[u]-dep[v]);
        if (u==v) return u;
        for (int i=DEG-1; i>=0; i--)
        {
            if (anc[u][i]!=anc[v][i])
            {
                u=anc[u][i];
                v=anc[v][i];
            }
        }
        return anc[u][0];
    }
    /************ segment tree *****************/
    int getdistance(int a,int b)
    {
        int _lca = lca(a,b);
        return cost[a]+cost[b]-2*cost[_lca];
    }
    vi tree[N<<2];  /// tree[i] 管辖的是以 i 为根节点的子树中相聚最远的两点
    vi max_dis_point(vi a,vi b)
    {
        for(int i=0; i<b.size(); i++)
        {
            a.push_back(b[i]);
        }
        vi ans;
        int _max = -1;
        for(int i=0; i<a.size(); i++)
        {
            for(int j=i+1; j<a.size(); j++)
            {
                int _distance = getdistance(a[i],a[j]);
                if(_distance>_max)
                {
                    _max = _distance;
                    ans.clear();
                    ans.push_back(a[i]);
                    ans.push_back(a[j]);
                }
            }
        }
        return ans;
    }
    void build(int l,int r,int idx)
    {
        if(l==r)
        {
            tree[idx].push_back(l);
            tree[idx].push_back(l);
            return;
        }
        int mid = (l+r)>>1;
        build(l,mid,idx<<1);
        build(mid+1,r,idx<<1|1);
        tree[idx] = max_dis_point(tree[idx<<1],tree[idx<<1|1]);
    }
    vi query(int l,int r,int L,int R,int idx)
    {
        vi ans;
        ans.clear();
        if (r < L || R < l) return ans;
        if(l >= L&& r <= R)
        {
            return tree[idx];
        }
        else
        {
            vi vl,vr;
            int mid = (l+r)>>1;
            vl =  query(l,mid,L,R,idx<<1);
            vr =  query(mid+1,r,L,R,idx<<1|1);
            return max_dis_point(vl,vr);
        }
    
    }
    int main()
    {
        while(scanf("%d%d",&n,&q)!=EOF)
        {
            init();
            for(int i=1; i<=4*n; i++) tree[i].clear();
            for(int i=1; i<n; i++)
            {
                int u,v,w;
                scanf("%d%d%d",&u,&v,&w);
                addEdge(u,v,w);
                addEdge(v,u,w);
            }
            dfs(1,0,0,0);
            getanc();
            build(1,n,1);
            while(q--)
            {
                int a,b;
                scanf("%d%d",&a,&b);
                vi ans = query(1,n,a,b,1);
                int res = 0;
                if(ans.size()==1)
                {
                    res = getdistance(ans[0],ans[0]);
                }
                else res = getdistance(ans[0],ans[1]);
                printf("%d
    ",res);
            }
        }
        return 0;
    }
  • 相关阅读:
    mysql 脚本
    一:spring boot 第一个程序启动遇到的问题及应对方案
    abp单元测试报错,出现异常解决办法 (system.directoryservices.protocols不能load该对象)
    如何实现 linq子查询
    Some times
    我的外婆
    男人之所以男人
    搭建自己网站【比如:博客】的方法
    搭建自己网站【比如:博客】的方法
    搭建自己网站【比如:博客】的方法
  • 原文地址:https://www.cnblogs.com/liyinggang/p/5943907.html
Copyright © 2020-2023  润新知