CIA2 城市网络(树上倍增)

来源:互联网 发布:远程教学软件zoom 编辑:程序博客网 时间:2024/06/15 06:41

题目描述

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

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

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

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

输入输出格式

输入格式:
第一行,两个正整数n,q。

第二行,n个正整数a[i]描述每个城市售卖的珠宝的价值。

接下来n-1行,每行描述一条道路x,y(1≤x,y≤n),表示有一条连接x和y的道路。

接下来q行,每行描述一次行程u,v,c(1≤u,v≤n)。

输出格式:
对于每次行程输出一行,为所购买次数。

输入输出样例

输入样例#1:
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
输出样例#1:
2
1
1
0
说明

对于100%的数据,保证2≤n≤10^5,1≤q≤10^5,1≤a​[i]≤10^​5,1≤c≤10^5​​。

时间限制:0.5s

内存限制:64M

首先对于每个点,预处理出离他最近的大于他的祖先(可以倍增预处理出mx[i][j]和fa[i][j],logn计算每个点),并建边,我们就得到了一个新的森林。然后对于新的森林,我们预处理出fa1[i][j]和mx1[i][j](同理),求x->y,以c开始的更新元素的次数,我们先在森林中对应的树上找到比c大的第一个数,作为起点x,然后往上走的话,一定是权值越来越大的(我们预处理了的结果),因此我们只需找到他最上能走到哪,记为y,则答案为dep1[x]-dep1[y]+1.
怎么找这个y呢?可以发现,在森林中,一棵树上的点从下往上的深度是单降的,因此我们只需再次倍增,找到dep[k]>= dep[y]的最上面的点k.
本题利用了三次树上倍增,极强。orz leoly

#include <bits/stdc++.h>using namespace std;#define ll long long#define inf 0x3f3f3f3f#define N 100010inline 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;}int n,q,a[N],h[N],num=0,fa[N][20],mx[N][20],dep[N],Log[N];int mx1[N][20],fa1[N][20],dep1[N];//mx[x][0]=max(a[x],a[fa[x]])struct edge{    int to,next;}data[N<<1];vector<int>son[N];void dfs(int x){    for(int i=1;i<=Log[n];++i){        if(!fa[x][i-1]) break;        fa[x][i]=fa[fa[x][i-1]][i-1];        mx[x][i]=max(mx[x][i-1],mx[fa[x][i-1]][i-1]);    }    for(int i=h[x];i;i=data[i].next){        int y=data[i].to;if(y==fa[x][0]) continue;        fa[y][0]=x;dep[y]=dep[x]+1;mx[y][0]=max(a[y],a[x]);dfs(y);    }}void dfs1(int x){    for(int j=1;j<=Log[n];++j){        if(!fa1[x][j-1]) break;        fa1[x][j]=fa1[fa1[x][j-1]][j-1];        mx1[x][j]=max(mx1[x][j-1],mx1[fa1[x][j-1]][j-1]);    }    for(int i=0;i<son[x].size();++i){        int y=son[x][i];        dep1[y]=dep1[x]+1;mx1[y][0]=max(a[y],a[x]);dfs1(y);    }}void getfa(int x){    int xx=x;//把x备份。。。     for(int i=Log[dep[x]]+1;i>=0;--i){        if(!fa[xx][i]) continue;        if(mx[xx][i]<=a[x]) xx=fa[xx][i];    }if(a[xx]>a[x]) fa1[x][0]=xx;else fa1[x][0]=fa[xx][0];    son[fa1[x][0]].push_back(x);}void solve(int x,int y,int val){    for(int i=Log[dep1[x]]+1;i>=0;--i){        if(!fa1[x][i]) continue;        if(mx1[x][i]<=val) x=fa1[x][i];    }int tmp= a[x]>val? dep1[x]:dep1[x]-1;    for(int i=Log[dep1[x]]+1;i>=0;--i){        if(!fa1[x][i]) continue;        if(dep[fa1[x][i]]>=dep[y]) x=fa1[x][i];    }    printf("%d\n",tmp-dep1[x]+1);}int main(){//  freopen("a1.in","r",stdin);    n=read();q=read();Log[0]=-1;    for(int i=1;i<=n;++i) a[i]=read(),Log[i]=Log[i>>1]+1;    for(int i=1;i<n;++i){        int x=read(),y=read();        data[++num].to=y;data[num].next=h[x];h[x]=num;        data[++num].to=x;data[num].next=h[y];h[y]=num;    }mx[1][0]=a[1];dfs(1);    for(int i=1;i<=n;++i) getfa(i);    for(int i=1;i<=n;++i) if(!fa1[i][0]) dfs1(i);    while(q--){        int x=read(),y=read(),v=read();        solve(x,y,v);    }    return 0;}
原创粉丝点击