zoukankan      html  css  js  c++  java
  • Codeforces Round #701 (Div. 2) E. Move and Swap

    题目链接:

    https://codeforces.com/problemset/problem/1485/E

    题解:

    dp。
    注意到在每一层中,蓝币的位置是任意的,而红币的位置是有限制的,仅能由父节点转移到儿子节点。
    考虑从上到下一层一层地转移,令dp[i]表示红币位于i号节点的最大答案,j表示i号节点的父亲,当我们不考虑换位时,显然:

    [dp[i]=dp[j]+max(|a_i-a_b|) ]

    其中(ab表示与i位于同一层的蓝币所处位置的值)。我们确定红币位置后,直接贪心取最大的|ai-ab|即可
    现考虑换位,则i可以是本层中任意一个位置(因为蓝币在本层中位置是任意的,你可以放好蓝币后与红币交换)。设换位前红币位于k,s是k的父亲,则:

    [dp[i]=max(dp[i],dp[s]+|a_i-a_k|) ]

    这样,对于每一个i,我们在这一层中枚举所有的位置取最优即可
    然而这样在每层中,每次更新是(O(n^2))的,全局复杂度也是(O(n^2))。现考虑如何优化:
    当ai>ak时,去掉绝对值,得:

    [dp[s]+|a_i-a_k|=dp[s]+a_i-a_k ]

    我们注意到,处理完上一层后,对于位置k,dp[s]-ak的值可以预处理。同理,当ai<ak时,dp[s]+ak的值也可以预处理。
    在每一层中,我们把当前层的点用一个vector来维护。我们对当前层的元素以ai为关键字升序排序,这样,处理第i个元素时,对于其前面的元素,我们取最大的dp[s]-ak,对于其后面的元素,我们取最大的dp[s]+ak。为了实现这点,我们考虑构造一个前缀数组pmax和后缀数组bmax来维护其最值,pmax[i]表示i前面所有元素中最大的dp[s]-ak,bmax[i]表示i后面所有元素中最大的dp[s]+ak
    这样,状态转移方程为:

    [dp[i]=max(dp[i],pamx[i]+a_i,bmax[i]-a_i) ]

    最后,我们考虑如何实现一层一层地枚举点。我是把所有点以深度为关键字排序,这样相同深度的点的下标就是一个连续的子段了,令L[i]表示深度为i的段的首端,R[i]为末端,在dp前处理出L[i],R[i]即可

    代码如下:

    注意我这里使用bmax维护的前缀,pmax维护的后缀


    #pragma GCC optimize(2)
    #include<bits/stdc++.h>
    using namespace std;
    struct front_star{
    	int to,next;
    }e[400005];
    struct poi{
    	int id,fa,d;
    	long long val;
    }node[200005];
    int T,n,cnt=0,mxd=0;
    long long ans=0;
    int head[200005],L[200005],R[200005];
    long long dp[200005],tpf[200005],tps[200005],pmx[200005],bmx[200005];
    vector<poi>f;
    inline int read()
    {
        int X=0,w=0; char ch=0;
        while(!isdigit(ch)) {w|=ch=='-';ch=getchar();}
        while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
        return w?-X:X;
    }
    inline long long maxn(long long a,long long b)
    {
    	return a>b?a:b;
    }
    inline void addedge(int u,int v)
    {
    	cnt++;
    	e[cnt].to=v;
    	e[cnt].next=head[u];
    	head[u]=cnt;
    }
    inline bool wcnmp(poi a,poi b)
    {
    	if(a.d<b.d)
    	   return true;
    	return false;      
    }
    inline void dfs(int u,int deep)
    {
    	mxd=maxn(deep,mxd);
    	node[u].d=deep;
    	for(register int i=head[u];~i;i=e[i].next)
    	{
    		int v=e[i].to;
    		if(v!=node[u].fa)
    		{
    			node[v].fa=node[u].id;
    			dfs(v,deep+1);
    		}
    	}
    }
    inline bool cmp(poi a,poi b)
    {
    	if(a.val<b.val)
    	   return true;
    	return false;    
    }
    int main()
    {
    	scanf("%d",&T);
    	while(T--)
    	{
    		cnt=0;
    		ans=0;
    		mxd=0;
    		memset(head,-1,sizeof(head));
    		scanf("%d",&n);
    		for(register int i=2;i<=n;i++)
    		{
    			int s;
    			s=read();
    			addedge(i,s);
    			addedge(s,i);
    		}
    		node[1].id=1;
    		node[1].val=0;
    		for(register int i=2;i<=n;i++)
    		{
    			node[i].id=i;
    			node[i].val=read();
    		}
    		node[1].fa=0;
    		dfs(1,1);
    		sort(node+1,node+1+n,wcnmp);
    		L[1]=1,R[mxd]=n;
    		int now=1;
    		for(register int i=1;i<=n;i++)
    		{
    			if(now!=node[i].d)
    			{
    				R[now]=i-1;
    				now++;
    				L[now]=i;
    			}
    		}
    		memset(dp,0,sizeof(dp));
    		for(register int i=2;i<=mxd;i++)
    		{
    			f.clear();
    			for(register int j=L[i];j<=R[i];j++)
    			    f.push_back(node[j]);
    			int upp=f.size();
    			sort(f.begin(),f.end(),cmp);
    			for(register int j=0;j<upp;j++)
    			{
    				bmx[j]=0;
    				pmx[j]=0;
    				tpf[j]=dp[f[j].fa]+f[j].val;
    				tps[j]=dp[f[j].fa]-f[j].val;
    			}
    			bmx[0]=tps[0];
    			pmx[upp-1]=tpf[upp-1];
    			for(register int j=1;j<upp;j++)
    				bmx[j]=maxn(bmx[j-1],tps[j]);
    			for(register int j=upp-2;j>=0;j--)
    			    pmx[j]=maxn(pmx[j+1],tpf[j]);	
    			for(register int j=0;j<upp;j++)
    			{
    				poi tp=f[j];
    				dp[tp.id]=maxn(dp[tp.id],dp[tp.fa]+f[upp-1].val-tp.val);
    				dp[tp.id]=maxn(dp[tp.id],dp[tp.fa]-f[0].val+tp.val);
    				dp[tp.id]=maxn(dp[tp.id],bmx[j]+tp.val);
    				dp[tp.id]=maxn(dp[tp.id],pmx[j]-tp.val);
    			}
    		}
    	    for(register int i=L[mxd];i<=R[mxd];i++)
    	        ans=maxn(dp[node[i].id],ans);
    		printf("%lld
    ",ans);    
    	}
    	return 0;
    } 
    /*
    1
    17
    1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 
    141742934 542155364 408860514 496518420 268022205 252909000 521914080 315254896 636214743 875364320 404786741 620328680 510764873 126572193 547542158 951490057
    */
    
    小鳥の翼がついに大きくなって , 旅立ちの日だよ , 遠くへと広がる海の色暖かく , 夢の中で描いた絵のようなんだ , 切なくて時をまきもどしてみるかい ? No no no いまが最高! だってだって、いまが最高!
  • 相关阅读:
    WeTypecho程序配置
    XX人事系统.nsi
    query-validate 插件
    数据库操作技巧 之 oracle连表update、跨库查询、恢复被删除数据、解决锁表
    Oracle中添加银行家四舍五入
    Java生成MD5的方法,简单封装并转为32位小写
    springMVC中使用oracle批量插入的书写方法
    前端ajax能访问到后台的controller中但是前端报错404
    远程连接Oracle 数据库连接报错ORA-12638身份检索失败
    SQL state [72000]; error code [1013]; ORA-03111: 通信通道收到中断; java.sql.SQLException: ORA-01745: 无效的主机/绑定变量名;java.sql.SQLException: ORA-01013: 用户请求取消当前的操作
  • 原文地址:https://www.cnblogs.com/nanjolno/p/14556436.html
Copyright © 2011-2022 走看看