zoukankan      html  css  js  c++  java
  • Codeforces 1000G Two-Paths 树形动态规划 LCA

    原文链接https://www.cnblogs.com/zhouzhendong/p/9246484.html

    题目传送门 - Codeforces 1000G Two-Paths

    题意

      给定一棵有 $n(2leq nleq 3 imes 10^5)$ 个节点的树,其中节点 $i$ 有权值 $a_i$,边 $e$ 有权值 $w_e$。$(1leq a_i,w_eleq 10^9)$

      现在给出 $q(1leq qleq 4 imes 10^5)$ 组询问,每组询问给定两个数 $x,y(1leq x,yleq n)$。

      如果一条路径的起点和终点分别为 $x$ 和 $y$,而且这条路径重复经过同一条边最多 $2$ 次(点可以多次经过),那么这条路径合法。

      一条合法路径 $P$ 的价值为 $Pr(p)$。$ ext{Pr}(p) = sumlimits_{v in ext{distinct vertices in } p}{a_v} - sumlimits_{e in ext{distinct edges in } p}{k_e cdot w_e}$。

      其中 $k_e$ 为路径 $p$ 经过 $e$ 的次数。

      每次询问问所有合法路径的最大价值。

    题解

      我们来跑一下树形dp。

      求出以下值。(下面是示意图,有填色的部分表示被计算)

      其中 $dp1,dp2,f1,sum$ 都表示所取的部分的合法最大值。

      

        

      

      再描述一下上面六个量的意义:

      dp1[x]:往 $x$ 的后代节点走最多可以赚多少。

      dp2[x]:往 $x$ 的祖先走最多可以赚多少。

      f1[x]:从 $x$ 的祖先向 $x$ 走最多可以赚多少。

      sum[x]:令树根到 $x$ 父亲的链为主链,假设主链上行走没有任何消耗和获益,向主链走最多可以获益多少。

      len[x]:$x$ 到根的距离(带边权)。

      s[x]:$x$ 的深度。

      

      在回答询问 $x,y$ 的时候,首先从 $x$ 到 $y$ 的路径一定被选,其中的边一定只走一次。

      其他的我们根据之前维护的量分类讨论加加减减一下就可以了。

      详见代码。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    const int N=300005,M=N*2;
    LL read(){
    	LL x=0;
    	char ch=getchar();
    	while (!('0'<=ch&&ch<='9'))
    		ch=getchar();
    	while ('0'<=ch&&ch<='9')
    		x=x*10+ch-48,ch=getchar();
    	return x;
    }
    struct Gragh{
    	int cnt,y[M],nxt[M],fst[N];
    	LL z[M];
    	void clear(){
    		cnt=0;
    		memset(fst,0,sizeof fst);
    	}
    	void add(int a,int b,LL c){
    		y[++cnt]=b,z[cnt]=c,nxt[cnt]=fst[a],fst[a]=cnt;
    	}
    }g;
    int n,q,fa[N][20],depth[N],xx,yy;
    LL a[N],dp1[N],f1[N],dp2[N],sum[N],fadis[N],len[N],s[N];
    void dfs1(int x,int pre,int d,LL L){
    	fa[x][0]=pre;
    	depth[x]=d;
    	len[x]=L;
    	s[x]=s[pre]+a[x];
    	for (int i=1;i<20;i++)
    		fa[x][i]=fa[fa[x][i-1]][i-1];
    	dp1[x]=0;
    	for (int i=g.fst[x];i;i=g.nxt[i]){
    		int y=g.y[i];
    		LL z=g.z[i];
    		if (y!=pre){
    			dfs1(y,x,d+1,L+z);
    			fadis[y]=z;
    			f1[y]=max(dp1[y]+a[y]-z*2,0LL);
    			dp1[x]+=f1[y];
    		}
    	}
    }
    void dfs2(int x,int pre,LL v,LL v2){
    	dp2[x]=v;
    	sum[x]=v2;
    	for (int i=g.fst[x];i;i=g.nxt[i]){
    		int y=g.y[i];
    		LL z=g.z[i];
    		if (y!=pre){
    			LL _v=max(v+a[x]+dp1[x]-f1[y]-2*z,0LL);
    			LL _v2=max(v2+dp1[x]-f1[y],0LL);
    			dfs2(y,x,_v,_v2);
    		}
    	}
    }
    int LCA(int x,int y){
    	if (depth[x]<depth[y])
    		swap(x,y);
    	for (int i=19;i>=0;i--)
    		if (depth[x]-(1<<i)>=depth[y])
    			x=fa[x][i];
    	if (x==y)
    		return x;
    	for (int i=19;i>=0;i--)
    		if (fa[x][i]!=fa[y][i])
    			x=fa[x][i],y=fa[y][i];
    	xx=x,yy=y;
    	return fa[x][0];
    }
    int main(){
    	scanf("%d%d",&n,&q);
    	for (int i=1;i<=n;i++)
    		a[i]=read();
    	g.clear();
    	for (int i=1;i<n;i++){
    		int a=read(),b=read();
    		LL c=read();
    		g.add(a,b,c);
    		g.add(b,a,c);
    	}
    	dfs1(1,0,0,0);
    	dfs2(1,0,0,0);
    	while (q--){
    		int x,y,lca;
    		scanf("%d%d",&x,&y);
    		if (depth[x]>depth[y])
    			swap(x,y);
    		lca=LCA(x,y);
    		if (x==lca){
    			if (y==lca){
    				printf("%I64d
    ",dp1[x]+dp2[x]+a[x]);
    				continue;
    			}
    			LL ans=s[y]-s[x]+a[x];
    			ans-=len[y]-len[x];
    			ans+=sum[y]-sum[x];
    			ans+=dp2[x]+dp1[y];
    			printf("%I64d
    ",ans);
    			continue;
    		}
    		LL ans=s[x]+s[y]-s[lca]*2+a[lca];
    		ans-=len[x]+len[y]-len[lca]*2;
    		ans+=sum[x]+sum[y]-sum[xx]-sum[yy];
    		ans+=dp1[lca]-f1[xx]-f1[yy];
    		ans+=dp2[lca]+dp1[x]+dp1[y];
    		printf("%I64d
    ",ans);
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    ZYAR20A 亚克力2驱 蓝牙 298寻迹避障机器人 —— 小车按键启动和蜂鸣器报警
    ZYAR20A 亚克力2驱 蓝牙 298寻迹避障机器人 —— 小车指定花式动作
    ZYAR20A 亚克力2驱 蓝牙 298寻迹避障机器人 —— 小车指定花式动作
    ZYAR20A 亚克力2驱 蓝牙 298寻迹避障机器人 —— 小车指定花式动作
    ZYAR20A 亚克力2驱 蓝牙 298寻迹避障机器人 —— 小车前后左右综合实验
    ZYAR20A 亚克力2驱 蓝牙 298寻迹避障机器人 —— 小车前后左右综合实验
    ZYAR20A 亚克力2驱 蓝牙 298寻迹避障机器人 —— 小车前后左右综合实验
    asp中设置session过期时间方法总结
    asp中设置session过期时间方法总结
    ASP.NET关于Session_End触发与否的问题
  • 原文地址:https://www.cnblogs.com/zhouzhendong/p/9246484.html
Copyright © 2011-2022 走看看