• 礼物 倍增


    礼物 倍增

    【题意描述】 喵国有 n 个城市,这 n 个城市由 n-1 条道路连通,每条道路恰好 把两个城市连通,小喵喵住在 1 号城市。 每一个城市都卖该城市的独有的纪念品。第 i 个城市的纪念品价 格为 A[i]。 现在小喵喵有 q 位朋友分别要找他玩,他们分别住在 S[j]城市中 (不在 1 号城市),并且会按照最短路径走到 1 号城市。他们在来之 前,首先会购买他们所在的城市的纪念品。然后在路上,每当他们所 在的城市卖的纪念品的价格高于他们手上的所有纪念品时,他就会买 一件当地的纪念品。(当到达 1 号城市时如果符合条件也会购买)之 后把这些纪念品都送给小喵喵。在他们回去时,也会在 1 号城市购买 纪念品,之后按照原路返回,同样地,如果当地的纪念品价格高于手 中所有纪念品,那么他会买一件当地的纪念品留作纪念。(当到达 S[j]号城市时如果符合条件也会购买) 现在小喵喵想知道他们分别会送给小喵喵多少件纪念品与一个数 X 的乘积,以及他们会带回去多少件纪念品与另一个数 Y 的乘积。

    【输入格式】 第 1 行三个个整数 n,X,Y,表示城市的个数,以及题目中的两 个系数。 第 2 行为用空格隔开的 n 个整数 a[i],表示每个城市的纪念品价 格。 第 3~n+1 行每行两个整数 u,v,表示 u 号城市和 v 号城市有道路 直接连接。 第 n+2 行一个整数 q,表示小喵喵的 q 次询问。 之后的 q 行,每行一个整数 s,表示他是从哪个城市出发的。

    【输出格式】 一共 q 行,每行两个整数,用空格隔开,分别表示小喵喵得到的 礼物数量和和他会带回的纪念品数量。

    对于返程我们直接一遍(dfs),维护从根节点到节点(i)经过的最大价格(mxg[i]),如果当前节点价格大于了父亲的(mxg),那么更新(mxg)和答案;

    对于去程,对于节点(u),我们要找到从叶子节点到根路径上第一个大于(val[u])的节点然后进行转移,这一点可以用树上倍增找到。考试时没想到倍增直接大力树剖炸了

    注意倍增中fa[1][0]=0

    #include <cstdio>
    #include <algorithm>
    using namespace std;
    inline int read(){
        char ch=getchar();int s=0;
        while(ch<'0'||ch>'9') ch=getchar();
        while(ch>='0'&&ch<='9') s=s*10+(ch^'0'),ch=getchar();
        return s;
    }
    #define MAXN 100010
    int head[MAXN],nxt[MAXN*2],vv[MAXN*2],tot;
    inline void add_edge(int u, int v){
        vv[++tot]=v;
        nxt[tot]=head[u];
        head[u]=tot;
    }
    int n,x,y;
    #define LOG 19
    int mxval[MAXN][LOG];
    int ff[MAXN][LOG];
    int mxg[MAXN],val[MAXN];
    int cnt1[MAXN];
    void dfs1(int u, int fa){
        ff[u][0]=fa;
        cnt1[u]=cnt1[fa];
        if(mxg[fa]<val[u])
            mxg[u]=val[u],++cnt1[u];
        else mxg[u]=mxg[fa];
        for(int i=head[u];i;i=nxt[i]){
            int v=vv[i];
            if(v==fa) continue;
            dfs1(v, u);
        }
    }
    inline int work(int x, int k){
        //printf("%d", x);
        for(int i=LOG-1;i>=0;--i)
            if(mxval[x][i]<=k)
                x=ff[x][i];
        //printf("=%d
    ", ff[x][0]);
        return ff[x][0];
    }
    int cnt2[MAXN];
    void dfs2(int u, int fa){
        int res=work(u, val[u]);
        cnt2[u]=cnt2[res]+1;
        for(int i=head[u];i;i=nxt[i]){
            int v=vv[i];
            if(v==fa) continue;
            dfs2(v, u);
        }
    }
    int main() {
        n=read(),x=read(),y=read();
        for(int i=1;i<=n;++i) val[i]=read();
        for(int i=1;i<n;++i){
            int u=read(),v=read();
            add_edge(u, v);
            add_edge(v, u);
        }
        dfs1(1, 0);
        for(int i=1;i<LOG;++i)
            for(int j=1;j<=n;++j)
                ff[j][i]=ff[ff[j][i-1]][i-1];
        for(int j=1;j<=n;++j) mxval[j][0]=val[ff[j][0]];
        for(int i=1;i<LOG;++i)
        for(int j=1;j<=n;++j)
            mxval[j][i]=max(mxval[j][i-1], mxval[ff[j][i-1]][i-1]);
        dfs2(1, 0);
        int q=read();
        while(q--){
            int s=read();
            printf("%d %d
    ", cnt2[s]*x, cnt1[s]*y);
        }
        return 0;
    }
    
  • 相关阅读:
    Mac下安装cscope和ctags
    MAC的VIMRC
    我的Linux系统的VIMRC
    关于在VI中查看BIN文件二进制值不对的问题
    没有关心过编写代码方式的好处,你是不是也是这样?
    四十不惑,真的不惑了么?
    jQuery通过text值来设置选定,以及遍历select的选项个数和遍历
    C#解析XML文件
    网页调用本地程序(Windows下浏览器全兼容)
    C#获取文件的md5
  • 原文地址:https://www.cnblogs.com/santiego/p/11835312.html
Copyright © 2020-2023  润新知