题目描述
JIH的玩具厂设立以来,发展了一张销售关系网。这张网以玩具厂为总代理(根),构成一颗树。每个节点都代表一个客户,且每个节点都有重要度ai。JIH想将这些客户划成若干类别,当然同一类的客户重要度相差太大总是不妥。所以JIH决定先进行市场调研。JIH会选择两个客户X,从X向根走一共k个节点进行调查。调查的结果是这条路径上重要程度相差最大的两个客户的差值是多少。因为特殊需要,要求重要度大的客户必须在重要度小的客户后面(顺序为X到根,若序列为递减,则输出0,详情见样例)。
输入
第一行一个整数N 表示N个客户
第二行N个整数Ai 表示N个客户的重要程度(工厂是1)
第三行开始 共N-1行 每行2个整数 x,y 表示x的父亲是y
接着一行一个正整数Q,表示Q次调研
接着Q行,每行两个整数X,K。含义见题目表述。
输出
Q行,每行一个正整数,含义见题目描述。
样例输入
6
5 6 1 7 5 2
2 1
3 1
4 2
5 2
6 3
3
4 3
6 2
6 3
样例输出
0
0
4
提示
数据范围:
30% 的数据中N,Q<=1000
100%的数据中N,Q<=200000 Ai<=1000000
这题的意思就是说,有q个询问,在x往根走k-1步的这条路上,最大的差值,且大的比小的离根更近。
我们可以用倍增法递推出所需的
max[i][j],min[i][j],ans[i][j](从i出发往上走2j步的路径上的最大值,最小值,最大差)
因为要保证大的离根更近,所以ans的递推需要这样:
for(int i=1;(1<for(int j=1;j<=n;j++)
{
f[j][i]=f[f[j][i-1]][i-1];
Max[j][i]=max(Max[j][i-1],Max[f[j][i-1]][i-1]);
Min[j][i]=min(Min[j][i-1],Min[f[j][i-1]][i-1]);
Ans[j][i]=max(Max[f[j][i-1]][i-1]-Min[j][i-1],max(Ans[j][i-1],Ans[f[j][i-1]][i-1])); //拆成两个区间a,b,再与b中max与a中min的差值进行比较
}
那么怎么处理询问呢?记得RMQ的话,就肯定知道它处理询问是由两个重叠的区间max或min产生最终答案的,我们也可以用这种方法,把询问的区间,拆成[a,c]、[b,d]两个区间
这样就有了一条线段 a b c d
再注意前面ans数组的定义,它只是当前区间内的最大差,这里还有一种情况,就是[c,d]中的max-[a,b]中的min,需要对这种情况再进行讨论。代码写得有点繁琐,领会思想就行。
#include
#include
#include
#include
using namespace std;
int n,q,x,y,z,t,w,l,r,tot,ans;
int a[200005],deep[200005],head[200005],Next[400005],to[400005];
int f[200005][18],Max[200005][18],Min[200005][18],Ans[200005][18];
void dfs(int k,int pre)
{
deep[k]=deep[pre]+1;
for(int i=head[k];i!=-1;i=Next[i])
if(to[i]!=pre)
{
f[to[i]][0]=k;
Max[to[i]][0]=max(a[k],a[to[i]]);
Min[to[i]][0]=min(a[k],a[to[i]]);
Ans[to[i]][0]=max(0,a[k]-a[to[i]]);
dfs(to[i],k);
}
}
void add(int x,int y)
{
tot++;
Next[tot]=head[x];
to[tot]=y;
head[x]=tot;
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<=n;i++) head[i]=-1;
for(int i=1;iscanf("%d%d",&x,&y);
add(x,y);
add(y,x);
}
dfs(1,0);
for(int i=1;(1<for(int j=1;j<=n;j++)
{
f[j][i]=f[f[j][i-1]][i-1];
Max[j][i]=max(Max[j][i-1],Max[f[j][i-1]][i-1]);
Min[j][i]=min(Min[j][i-1],Min[f[j][i-1]][i-1]);
Ans[j][i]=max(Max[f[j][i-1]][i-1]-Min[j][i-1],max(Ans[j][i-1],Ans[f[j][i-1]][i-1]));
}
cin>>q;
for(int i=1;i<=q;i++)
{
scanf("%d%d",&x,&y);
y--;
if(y==0)
{
printf("0\n");
continue;
}
t=y;
z=0;
while(t>0)
{
z++;
t=t/2;
}
z--;
ans=Ans[x][z]; //第一个区间
t=y-(1<for(int j=17;j>=0;j--)
if((t&(1<1<//第二个区间 x,w,x+(1<
if(z>0)
{
int v=0;
l=f[x][z];
r=f[w][z];
for(int j=17;j>=0;j--)
if(deep[f[l][j]]>=deep[r])
{
v=max(v,Max[l][j]);
l=f[l][j];
}
int o=1e9;
l=x;
r=w;
for(int j=17;j>=0;j--)
if(deep[f[l][j]]>=deep[r])
{
o=min(o,Min[l][j]);
l=f[l][j];
}
ans=max(ans,v-o);
}
printf("%d\n",ans);
}
return 0;
}