• hdu 3078 Network (暴力)+【LCA】


    <题目链接>

    题目大意:
    给定一颗带点权的树,进行两种操作,k=0,更改某一点的点权,k!=0,输出a~b路径之间权值第k大的点的点权。

    解题分析:
    先通过RMQ的初始化,预处理pre[]数组,并且求出a和b的LCA。然后利用LCA将a、b路径上所有点的点权全部存储起来,将其排序,就可得到a、b路径上权值第k大的点权。具体操作为:利用pre[]数组,从a到LCA的所有点权全部相加,然后再将从b到LCA的所有点权相加,就可以得到a、b路径上所有点的点权。下面用的是LCA转RMQ的方法求解。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    using namespace std;
     
    const int maxn = 8e4+10;
    struct Edge{
        int to,next;
    }edge[maxn<<1];
    int n,q,cnt,num,tot,pre[maxn],val[maxn],fa[maxn];
    int st[maxn<<1][20],ver[maxn<<1],dep[maxn<<1],first[maxn],path[maxn];
    
    bool cmp(int a,int b){ return a > b;}
    int Min(int l,int r){
        return dep[l]<dep[r]?l:r;
    } 
    void addedge(int u,int v){
        edge[num].to = v,edge[num].next = pre[u];
        pre[u] = num++;
    }
    void dfs(int u,int deep){
        ver[++cnt] = u; first[u] = cnt; dep[cnt] = deep;
        for(int i = pre[u]; i != -1; i = edge[i].next){
            int v = edge[i].to;
            if(fa[u] == v) continue;
            fa[v] = u;
            dfs(v,deep+1);
            ver[++cnt] = u; dep[cnt] = deep;
        }
    }
    void RMQ_init(){
        for(int i = 1; i <= cnt; i++)
            st[i][0] = i;
        for(int j = 1; (1 << j) <= cnt; j++)
            for(int i = 1; i + (1 << j) < cnt; i++)
                st[i][j] = Min(st[i][j-1],st[i+(1<<(j-1))][j-1]);
    }
    int findLCA(int l,int r){
        int k = (int)(log(r - l + 1.0) / log(2.0));
        return ver[Min(st[l][k],st[r-(1<<k)+1][k])];
    }
    //以上是LCA转RMQ的模板
    int main(){
        int k,a,b;
        while(scanf("%d%d",&n,&q)!=EOF){
            cnt = num = 0;
            memset(pre,-1,sizeof(pre));
            for(int i = 1; i <= n; i++)
                scanf("%d",&val[i]);
            for(int i = 1; i < n; i++){
                scanf("%d%d",&a,&b);
                addedge(a,b);
                addedge(b,a);
            }
            dfs(1,0);
            RMQ_init();
            while(q--){
                scanf("%d%d%d",&k,&a,&b);
                if(k == 0)val[a] = b;
                else{
                    int x = first[a], y = first[b];
                    if(x > y) swap(x,y);
                    int lca = findLCA(x,y);    //得到最近公共祖先
                    tot = 0;
                    while(a != lca){    //将a到最近公共祖先的路劲上所有的点权放入path数组
                        path[++tot] = val[a];
                        a = fa[a];
                    }
                    while(b != lca){    //将a到最近公共祖先的路劲上所有的点权放入path数组
                        path[++tot] = val[b];
                        b = fa[b];
                    }
                    path[++tot] = val[lca];   //再加上lca的点权
                    if(k > tot) printf("invalid request!
    ");
                    else{
                        sort(path+1,path+1+tot,cmp);   //将a->b路劲上所有点权排序,然后就可以得到第k大的点权
                        printf("%d
    ",path[k]);
                    }
                }
            }
        }
        return 0;
    }

    2018-10-23

  • 相关阅读:
    [BZOJ 3270] 博物馆
    [BZOJ 3551] Peaks加强版
    [HNOI 2009] 梦幻布丁
    [NOI 2018] 归程
    [YNOI 2016] 掉进兔子洞
    [SCOI 2014] 方伯伯的玉米田
    Codeforces Round #545 (Div. 2)
    初涉Min-Max容斥【在更】
    【费用流】bzoj1834: [ZJOI2010]network 网络扩容
    【最大权闭合子图】bzoj4873: [Shoi2017]寿司餐厅
  • 原文地址:https://www.cnblogs.com/00isok/p/9840520.html
Copyright © 2020-2023  润新知