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;}
- CIA2 城市网络(树上倍增)
- *树上倍增(LCA)
- 树上倍增解析(转载)
- 树上倍增
- NOIP 2013 货车运输(树上倍增)
- [BZOJ3732]Network(kruskal+树上倍增)
- 树链上的完全背包(树上倍增)
- NOIP模拟:情报传输(树上倍增)
- 美团点评2017年CodeM大赛-复赛 A 城市网络(倍增)
- 【树上倍增算法模板】
- cf588e & bzoj3306 树上倍增
- noip2013truck树上路径倍增
- 3306: 树 树上倍增
- 树上倍增实现lca
- 树上倍增求LCA
- 【复习记录】树上倍增
- 美团CODEM 复赛 城市网络 询问离线,树上LCA
- 树上倍增求LCA(最近公共祖先)
- C语言实验——单个字符输入和输出(顺序结构)
- 递归方法入门
- centos6永久修改主机名
- 【poj 2478】 Farey Sequence
- inline的用法
- CIA2 城市网络(树上倍增)
- 秋招详细攻略——从准备到面试
- HDU
- 输入一个链表,输出该链表中倒数第k个结点。
- 拉格朗日乘数法
- hdu1197 Specialized Four-Digit Numbers
- Java Activiti(7)--任务办理
- C语言实验——转换字母(顺序结构)
- 支付宝电脑支付,微信扫码支付