城市网络---------------倍增

题目描述

有一个树状的城市网络(即 n个城市由 n−1条道路连接的连通图),首都为 1号城市,每个城市售卖价值为 ai的珠宝。你是一个珠宝商,现在安排有 q次行程,每次行程为从 u号城市前往 v号城市(走最短路径),保证 v在 u前往首都的最短路径上。在每次行程开始时,你手上有价值为 c的珠宝(每次行程可能不同),并且每经过一个城市时(包括 u和 v),假如那个城市中售卖的珠宝比你现在手上的每一种珠宝都要优秀(价值更高,即严格大于),那么你就会选择购入。现在你想要对每一次行程,求出会进行多少次购买事件。 输入格式第一行,两个正整数 n,q。第二行,n个正整数ai描述每个城市售卖的珠宝的价值。接下来 n−1行,每行描述一条道路x,y (1≤x,y≤n),表示有一条连接 x和 y的道路。接下来 q 行,每行描述一次行程 u,v,c (1≤u,v≤n)。 输出格式对于每次行程输出一行,为所购买次数。

样例输入

5 4

3 5 1 2 4

1 2

1 3

2 4

3 5

4 2 1

4 2 2

4 2 3

5 1 5

样例输出

2

1

1

0

数据范围与提示

对于 100%的数据,保证 2≤n≤10^5,1≤q≤10^5, 1≤ai≤10^5, 1≤c≤10^5。


    可以发现,一旦开始购买,那么接下来购买的“行程”就可以确定下来了。

       其实这种定式的行走路线完全可以归属于每个节点,其实就是说我们可以预处理出每个节点相关的接下来的行走路线。

            n2 是不可能的,我们可以模仿树上倍增求 LCA 的做法------运用强大的二进制操作:倍增。

            定义倍增数组 f 【i】【j】表示若选择 i 号节点则接下来第 2 Λ j 步到的节点编号。(这里的步是指有贡献的 ‘ 步 ’ )

            具体而言,我们对于每一个节点预处理出离它最近且权值大于它的祖先,那么这个祖先节点就是经过当前节点后接下

              来会产生贡献的节点(其他节点就直接跳过了)。

            如何得到这个点呢?既然是有关祖先节点的信息,我们便可以利用已经处理好了的祖先的倍增数组来求得。也就是利

              用倍增数组来求倍增数组,且前者是已经处理好了的。

            对于询问,我们先从起点跳到询问路径中的有效节点中最后一个不会产生贡献的节点(特判从起点开始就产生贡献的

              情况),接下来我们只需要一直沿着倍增数组往上跳直至跳到终点就可以了。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int n,m,x,y,z,v[200050];
 4 int head[200050],nex[400050],ver[400050],tot;
 5 int dep[200050],f[200050][20];
 6 int t[200050],dfn[200050],cnt,top,ans;
 7 int tx[200050];
 8 void add(int x,int y)
 9 {
10     nex[++tot]=head[x];
11     ver[tot]=y;
12     head[x]=tot;
13 }
14 void dfs(int u,int fa)
15 {
16     dep[u]=dep[fa]+1;
17     int tmp=fa;
18     for(int i=18;i>=0;--i)
19         if(v[f[tmp][i]]<=v[u])
20             tmp=f[tmp][i];
21     if(v[tmp]>v[u])
22         f[u][0]=tmp;
23     else
24         f[u][0]=f[tmp][0];
25     for(int k=1;k<=18;++k)
26         f[u][k]=f[f[u][k-1]][k-1];
27     for(int i=head[u];i;i=nex[i])
28         if(ver[i]!=fa)
29             dfs(ver[i],u);
30 }
31 void calc()
32 {
33     for(int i=18;i>=0;--i)
34         if(v[f[x][i]]<=z)
35             x=f[x][i];
36     if(dep[x]<dep[y])
37         return ;
38     if(v[x]>z)
39         ++ans;
40     for(int i=18;i>=0;--i)
41         if(dep[f[x][i]]>=dep[y])
42         {
43             x=f[x][i];
44             ans+=(1<<i);
45         }
46 }
47 int main()
48 {
49     scanf("%d%d",&n,&m);v[0]=0x7fffffff;
50     for(int i=1;i<=n;++i)
51         scanf("%d",&v[i]);
52     for(int i=1;i<n;++i)
53     {
54         scanf("%d%d",&x,&y);
55         add(x,y); add(y,x);
56     }
57     dfs(1,0);
58     while(m--)
59     {
60         scanf("%d%d%d",&x,&y,&z);
61         ans=0;calc();
62         printf("%d
",ans);
63     }
64     return 0;
65 }
代码
原文地址:https://www.cnblogs.com/wyher/p/9815763.html