礼物 倍增
礼物 倍增
【题意描述】 喵国有 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;
}