[美团 CodeM 复赛]城市网络

xiaoxiao2021-02-28  59

题目描述

有一个树状的城市网络(即 nnn 个城市由 n−1n-1n−1 条道路连接的连通图),首都为 111 号城市,每个城市售卖价值为 aia_ia​i​​ 的珠宝。

你是一个珠宝商,现在安排有 qqq 次行程,每次行程为从 uuu 号城市前往 vvv 号城市(走最短路径),保证 vvv 在 uuu 前往首都的最短路径上。

在每次行程开始时,你手上有价值为 ccc 的珠宝(每次行程可能不同),并且每经过一个城市时(包括 uuu 和 vvv),假如那个城市中售卖的珠宝比你现在手上的每一种珠宝都要优秀(价值更高,即严格大于),那么你就会选择购入。

现在你想要对每一次行程,求出会进行多少次购买事件。

倍增

对每个位置倍增求出祖先中第一个大于自己的,然后可以建出新的树(其实是森林如果你当0号点不存在的话)。 每次询问倍增求出u的祖先中第一个大于自己的位置(注意判断这个是否在v以下),然后再在新树上倍增。

#include<cstdio> #include<algorithm> #include<cmath> #define fo(i,a,b) for(i=a;i<=b;i++) using namespace std; const int maxn=100000+10; int h[maxn],go[maxn*2],nxt[maxn*2],a[maxn]; int h2[maxn],g2[maxn*2],n2[maxn*2]; int f[maxn][25],g[maxn][25],dep[maxn],dp[maxn],fa[maxn][25],zjy[maxn],d[maxn]; int i,j,k,l,t,n,m,tot,top,ans; int read(){ int x=0,f=1; char ch=getchar(); while (ch<'0'||ch>'9'){ if (ch=='-') f=-1; ch=getchar(); } while (ch>='0'&&ch<='9'){ x=x*10+ch-'0'; ch=getchar(); } return x*f; } void add(int x,int y){ go[++tot]=y; nxt[tot]=h[x]; h[x]=tot; } void add2(int x,int y){ d[y]++; g2[++tot]=y; n2[tot]=h2[x]; h2[x]=tot; } void dfs(int x,int y){ dep[x]=dep[y]+1; f[x][0]=y; g[x][0]=a[x]; int t=h[x]; while (t){ if (go[t]!=y) dfs(go[t],x); t=nxt[t]; } } void dg(int x){ int t=h2[x]; while (t){ fa[g2[t]][0]=x; dp[g2[t]]=dp[x]+1; dg(g2[t]); t=n2[t]; } } int main(){ //freopen("B.in","r",stdin); n=read();m=read(); fo(i,1,n) a[i]=read(); fo(i,1,n-1){ j=read();k=read(); add(j,k);add(k,j); } dfs(1,0); fo(i,1,n) zjy[i]=floor(log(i)/log(2)); fo(j,1,zjy[n]) fo(i,1,n){ f[i][j]=f[f[i][j-1]][j-1]; g[i][j]=max(g[i][j-1],g[f[i][j-1]][j-1]); } tot=0; fo(i,2,n){ t=f[i][0]; j=zjy[dep[t]]; k=0; while (j>=0){ if (g[t][j]<=a[i]) t=f[t][j]; j--; } if (a[t]>a[i]) add2(t,i); } fo(i,1,n) if (!d[i]){ dp[i]=1; dg(i); } fo(j,1,zjy[n]) fo(i,1,n) fa[i][j]=fa[fa[i][j-1]][j-1]; while (m--){ t=read();k=read();l=read(); j=zjy[dep[t]]; while (j>=0){ if (g[t][j]<=l) t=f[t][j]; j--; } if (a[t]<=l||dep[t]<dep[k]) printf("0\n"); else{ ans=dp[t]; j=zjy[dp[t]]; while (j>=0){ if (dep[fa[t][j]]>=dep[k]) t=fa[t][j]; j--; } ans-=dp[t]; ans++; printf("%d\n",ans); } } }
转载请注明原文地址: https://www.6miu.com/read-19377.html

最新回复(0)