礼物 倍增

礼物 倍增

【题意描述】 喵国有 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\n", 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\n", cnt2[s]*x, cnt1[s]*y);
    }
    return 0;
}
posted @ 2019-11-11 15:27  Santiego  阅读(88)  评论(0编辑  收藏  举报