• 城市网络


    城市网络

    Problem:

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

    Input:

    第一行,两个正整数 (n , q (2 ≤ n ≤ 10^5 , 1 ≤ q ≤ 10^5))。 第二行,n 个正整数 (a_i (1 ≤ a_i ≤ 10^5)) 描述每个城市售卖的珠宝的价值。 接下来 n-1 行,每行描述一条道路 (x , y (1 ≤ x,y ≤ n)),表示有一条连接 x 和 y 的道路。 接下来 q 行,每行描述一次行程 (u , v , c (1 ≤ u,v ≤ n , 1 ≤ c ≤ 10^5))

    Output:

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

    Example:

    Input

    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
    

    Output

    2
    1
    1
    0
    

    题解:

    树上倍增,ST表,由于每次经过一个城市我们都会选择是否购买珠宝,决策后手上的珠宝都是经过路径上价值最大的珠宝,所以我们需要知道在需要经过的路径上,珠宝价值不断递增的城市有多少,本题如果用暴力方法,最差情况下会是O(n*q)的时间复杂度,显然这是不行的。本体应该用st表去维护每个节点上需要经过几个不断递增的节点,st表的递推式:

    [st[i][j]=st[st[i][j-1]][j-1] ]

    (st[i][j])表示从i点开始能买(2^j)个珠宝的点是哪个,所以如果一直(st[i][0])的值,那么i往上买(2^j)个珠宝的点,可以由i往上买(2^j-1)个珠宝的点再买(2^{j-1})个珠宝的点,所以递推式如上。对于(st[i][0])我们也可以用倍增的方式求,但是我们用从大到小枚举j值,这样就可以找到最远的可以买到1个珠宝的位置(如果枚举到的位置比当前权值小则需要继续向上倍增(倍增长度减少一半,因为原长度倍增的话则相当于已经倍增过的长度))。

    经过ST表处理后的树,对于每次查询我们只需要查询从u开始,且深度大于等于v的点数之和(映射到ST表中就是满足条件的倍增长度的总和)。

    关于ST表:https://www.cnblogs.com/LeafLove/p/12345136.html

    Code:

    /**********************************************************
    * @Author: 			   Kirito
    * @Date:   			   2020-07-27 08:15:25
    * @Last Modified by:   Kirito
    * @Last Modified time: 2020-07-27 09:27:55
    * @Remark: 
    **********************************************************/
    #include <bits/stdc++.h>
    #define lowbit(x) (x&(-x))
    #define CSE(x,y) memset(x,y,sizeof(x))
    #define INF 0x3f3f3f3f
    #define Abs(x) (x>=0?x:(-x))
    #define FAST ios::sync_with_stdio(false);cin.tie(0);
    using namespace std;
    
    typedef long long ll;
    typedef pair<int,int> pii;
    typedef pair<ll , ll> pll;
    
    const int maxn=211111;
    vector<int> v[maxn];
    int a[maxn],f[maxn][20],dep[maxn],to[maxn];
    
    void dfs(int p,int fa)
    {
    	int x=fa;
    	for(int k=19;k>=0;k--){
    		if(f[x][k]&&a[f[x][k]]<=a[p]) x=f[x][k];
    	}
    	if(a[x]>a[p]) f[p][0]=x;
    	else f[p][0]=f[x][0];
    
    	for(int i=1;i<20;i++)
    		f[p][i]=f[f[p][i-1]][i-1];
    
    	dep[p]=dep[fa]+1;
    
    	for(auto t:v[p]){
    		if(t==fa) continue;
    		dfs(t,p);
    	}
    	return;
    }
    
    int n,q;
    
    int main()
    {
    	#ifndef ONLINE_JUDGE
    	freopen("in.in","r",stdin);
    	#endif
    	FAST;
    	cin>>n>>q;
    	for(int i=1;i<=n;i++)
    		cin>>a[i];
    	for(int i=0;i<n-1;i++){
    		int x,y;
    		cin>>x>>y;
    		v[x].push_back(y);
    		v[y].push_back(x);
    	}
    	for(int i=n+1;i<=n+q;i++){
    		int x,y,c;
    		cin>>x>>y>>c;
    		v[i].push_back(x);
    		v[x].push_back(i);
    		a[i]=c;
    		to[i-n]=y;
    	}
    	dfs(1,0);
    	for(int i=1;i<=q;i++){
    		int ans=0;
    		int x=i+n;
    		for(int k=19;k>=0;k--){
    			if(dep[f[x][k]]>=dep[to[i]]){
    				ans+=(1<<k);
    				x=f[x][k];
    			}
    		}
    		cout<<ans<<endl;
    	}
    	return 0;
    }
    
  • 相关阅读:
    【实战】一次简单的js接口漏洞挖掘
    【实战】Location 302跳转 + CRLF 场景下的XSS
    【实战】权限绕过小结
    【实战】简单的API接口FUZZ小案例
    【实战】一次有趣的逻辑漏洞挖掘
    【实战】一个简单的SQL注入绕过
    【实战】springboot actuator未授权访问之trace接口泄漏敏感信息
    【实战】springboot actuator未授权访问之heapdump敏感信息提取
    层次分析法AHP
    pyppeteer(1)
  • 原文地址:https://www.cnblogs.com/LeafLove/p/13384294.html
Copyright © 2020-2023  润新知