Solution
题目中有两个关键信息:
- 1号节点是根节点。
- 节点 在节点 到根节点的最短路径上。
由于是树形结构,所以从 到 一定是不断地将 ,也就是 是 的祖先。
于是可以先进行一次 预处理出每个节点的父节点,之后回答询问。只有当某个节点的珠宝比手中的都值钱是才会采购,所以一旦出现更有价值的,其他珠宝就没有比较的价值了。于是可以联系到单调栈。
具体来说,遇到比栈顶更有价值的珠宝时进行弹栈。如果弹完后栈中没有元素,则证明比当前的所有珠宝更有价值,就可以使答案加 ,再将此珠宝加入栈中即可。
时间复杂度: 。
Code
#include <iostream> #include <cstdio> using namespace std; const int maxn=1e5+10; int n,q,cnt,tp,ans,a[maxn],hd[maxn],fa[maxn],s[maxn]; struct edge{ int t; int v; }e[maxn<<1]; void add(int x,int y){ cnt++; e[cnt].t=hd[x]; e[cnt].v=y; hd[x]=cnt; } void Dfs(int u,int x){ fa[u]=x; for(int i=hd[u];i!=0;i=e[i].t) if(e[i].v!=x) Dfs(e[i].v,u); } int Query(int x,int y,int c){ ans=tp=0; s[++tp]=0; a[0]=c; while(1){ while(a[s[tp]]<a[x]&&tp>0) tp--; if(!tp){ s[++tp]=x; ans++; } if(x==y) break; x=fa[x]; } return ans; } int main(){ ios::sync_with_stdio(false); cin>>n>>q; for(int i=1;i<=n;i++) cin>>a[i]; int x,y,z; for(int i=1;i<n;i++){ cin>>x>>y; add(x,y); add(y,x); } Dfs(1,1); for(int i=1;i<=q;i++){ cin>>x>>y>>z; cout<<Query(x,y,z)<<endl; } return 0; }
仔细考虑之后,发现这是一个找祖先的过程。联系倍增求 根据本道题的状态,可以设 为节点 之上的第 个采购珠宝的节点,则有
所以可以用一次 预处理出 数组,之后回答询问即可。由于询问的珠宝价格是独立的,所以可以新建一个节点并向询问中的 节点连边。
时间复杂度 。
#include <iostream> #include <cstdio> using namespace std; const int maxn=2e5+10; int n,q,cnt,ans,a[maxn],hd[maxn],dep[maxn],f[20][maxn],b[maxn]; struct edge{ int t; int v; }e[maxn<<1]; void add(int x,int y){ cnt++; e[cnt].t=hd[x]; e[cnt].v=y; hd[x]=cnt; } void Dfs(int u,int fa){ dep[u]=dep[fa]+1; int x=fa; if(a[fa]>a[u]) f[0][u]=fa; else{ for(int i=19;i>=0;i--) if(f[i][fa]&&a[f[i][fa]]<=a[u]) fa=f[i][fa]; f[0][u]=f[0][fa]; } for(int i=1;i<=19;i++) f[i][u]=f[i-1][f[i-1][u]]; for(int i=hd[u];i!=0;i=e[i].t) if(e[i].v!=x) Dfs(e[i].v,u); } int main(){ ios::sync_with_stdio(false); cin>>n>>q; for(int i=1;i<=n;i++) cin>>a[i]; int x,y,z; for(int i=1;i<n;i++){ cin>>x>>y; add(x,y); add(y,x); } for(int i=1;i<=q;i++){ cin>>x>>y>>z; add(n+i,x); add(x,n+i); a[n+i]=z; b[i]=y; } Dfs(1,0); for(int i=1;i<=q;i++){ x=n+i,y=b[i],ans=0; for(int j=19;j>=0;j--) if(dep[f[j][x]]>=dep[y]){ ans+=(1<<j); x=f[j][x]; } cout<<ans<<endl; } return 0; }