題意簡述
有 個城市,組成一張樹形網絡。第 個城市售賣價值爲 的珠寶。zps 的父母計劃了 次行程。每次先帶上價值爲 的珠寶,從城市 走到城市 (保證 在 到 的路徑上)。如果當前的城市售賣的珠寶比手頭的貴(嚴格大於,等於不行),那麼 zps 的父母會買入這個珠寶。
對於每次行程,求出 zps 的父母進行了多少次“買入”操作。
,
思路
我們發現,對於每一次行程,除了第一次要特判一下之外,我下一次走到哪裏應該是固定的。
假設我們當前在 ,那麼我們下一次走的位置,應該就是 往上跳,第一個 的 (當然,如果這個 跳到了 外面,那麼我們不算它)
於是我們考慮,先用倍增求出第一個 的 ,然後重新建圖,把 直接連到 上。這樣,對於每次行程,我們把首尾特判掉之後,就相當於新樹上求一段路徑的長度了。這個直接維護一個深度就能求了。
代碼
#include <bits/stdc++.h>
using namespace std;
namespace Flandre_Scarlet
{
#define N 155555
#define F(i,l,r) for(int i=l;i<=r;++i)
#define D(i,r,l) for(int i=r;i>=l;--i)
#define Fs(i,l,r,c) for(int i=l;i<=r;c)
#define Ds(i,r,l,c) for(int i=r;i>=l;c)
#define MEM(x,a) memset(x,a,sizeof(x))
#define FK(x) MEM(x,0)
#define Tra(i,u) for(int i=G.Start(u),v=G.To(i);~i;i=G.Next(i),v=G.To(i))
#define p_b push_back
#define sz(a) ((int)a.size())
#define iter(a,p) (a.begin()+p)
int I()
{
int x=0;char c=getchar();int f=1;
while(c<'0' or c>'9') f=(c=='-')?-1:1,c=getchar();
while(c>='0' and c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
return (x=(f==1)?x:-x);
}
void Rd(int cnt,...)
{
va_list args; va_start(args,cnt);
F(i,1,cnt) {int* x=va_arg(args,int*);(*x)=I();}
va_end(args);
}
class Graph
{
public:
int head[N];
int EdgeCount;
struct Edge
{
int To,Label,Next;
}Ed[N<<1];
void clear(int _V=N,int _E=N<<1)
{
memset(Ed,-1,sizeof(Edge)*(_E));
memset(head,-1,sizeof(int)*(_V));
EdgeCount=-1;
}
void AddEdge(int u,int v,int w=1)
{
Ed[++EdgeCount]=(Edge){v,w,head[u]};
head[u]=EdgeCount;
}
void Add2(int u,int v,int w=1) {AddEdge(u,v,w);AddEdge(v,u,w);}
int Start(int u) {return head[u];}
int To(int u){return Ed[u].To;}
int Label(int u){return Ed[u].Label;}
int Next(int u){return Ed[u].Next;}
}G;
int n,m;
int a[N];
void Input()
{
Rd(2,&n,&m);
F(i,1,n) a[i]=I();
G.clear();
F(i,1,n-1)
{
int u,v; Rd(2,&u,&v); G.Add2(u,v);
}
}
int deep[N],fa[N][22],Max[N][22];
void DFS(int u,int f)
{
deep[u]=(u==f)?0:deep[f]+1;
fa[u][0]=f; F(i,1,20) fa[u][i]=fa[fa[u][i-1]][i-1];
Max[u][0]=max(a[u],a[f]); F(i,1,20) Max[u][i]=max(Max[u][i-1],Max[fa[u][i-1]][i-1]);
Tra(i,u) if (v!=f) DFS(v,u);
}
int PathMax(int u,int f) // 求路徑最大值
{
if (u==f) return a[u];
int ans=0;
D(i,20,0) if (deep[fa[u][i]]>=deep[f])
{
ans=max(ans,Max[u][i]),u=fa[u][i];
}
return ans;
}
int MaxPos(int u,int f) // 求路徑最大值是哪個位置
{
int Mx=PathMax(u,f);
if (a[u]==Mx) return u;
D(i,20,0) if (Max[u][i]<Mx) u=fa[u][i];
return fa[u][0];
}
int FirstBig(int u,int c) // 找到 u 往上第一個滿足 a[i]>c 的
{
if (a[u]>c) return u;
if (Max[u][20]<=c) return n+1;
D(i,20,0) if (Max[u][i]<=c) u=fa[u][i];
return fa[u][0];
}
namespace Re_build // 把重新建的圖封裝起來,避免名字衝突
{
Graph G;
int deep[N],fa[N][22];
void Init()
{
G.clear();
F(i,1,n) G.AddEdge(fa[i][0],i);
}
void DFS(int u)
{
deep[u]=(u==n+1)?0:deep[fa[u][0]]+1;
F(i,1,20) fa[u][i]=fa[fa[u][i-1]][i-1];
Tra(i,u) DFS(v);
}
int Query(int u,int fu) {return deep[u]-deep[fu];}
}
void Soviet()
{
DFS(1,1);
F(i,1,n) Re_build::fa[i][0]=(Max[i][20]==a[i])?n+1:FirstBig(i,a[i]);
// 重新設置 fa 數組
Re_build::Init();
Re_build::DFS(n+1);
// 重新 DFS 一遍
F(i,1,m)
{
int u,v,c; Rd(3,&u,&v,&c);
int uu=u,vv=v; // 存儲原始的 u,v (後面會有修改)
if (u==v) {puts(c<a[u]?"1":"0"); continue;}
if (c>=PathMax(u,v)) {puts("0"); continue;}
u=FirstBig(uu,c); // 先跳到上面第一個 >c 的 (注意,這裏先跳了一次,所以答案+1)
v=MaxPos(uu,vv); // 處理一下開頭結尾
printf("%d\n",Re_build::Query(u,v)+1);
// 如上面所說,答案 +1
}
}
#define Flan void
Flan IsMyWife()
{
Input();
Soviet();
}
}
int main()
{
Flandre_Scarlet::IsMyWife();
getchar();getchar();
return 0;
}