首页 > 其他分享 >AT_ddcc2020_final_d Pars/ey

AT_ddcc2020_final_d Pars/ey

时间:2023-09-23 16:33:52浏览次数:41  
标签:int ddcc2020 nd dead ey maxn nd1 Pars nd2

AT_ddcc2020_final_d Pars/ey

重工业题。

找环然后树形 DP 是显然的,先考虑断开环上的边怎么做。

把环复制一遍放在结尾,记 \(sum_i\) 为环长的前缀和,\(f_i\) 为该子树内的最长根链的长度,问题变为每次给定一个区间,要求找到 \(i,j(i>j)\) 使得 \(sum_i-sum_j+f_i+f_j\) 最大,可以使用线段树实现。注意要与同一棵树里的直径取 max(大概有 \(\mathcal O(n)\) 做法吧)

然后考虑树边如何处理。先求出不删边时基环树的直径,如果是树内的直径那么删其他边不会对答案造成影响,所以只需计算该子树。直径经过了环可以对两个端点所在的树计算两次。

断了树边后基环树的直径有 2 种情况:直径至少有一端在这棵树里和不在这棵树里。两端都在树外面是好处理的,对于第一种情况可以类似换根的方法处理。

image.png

1.直径为蓝色或红色的路径。

蓝色的路径是好处理的,对于每棵子树维护子树内直径即可。

对于红色,因为换根到儿子时红色路径的长度可以继承父亲的,所以只需要一个变量记录当前红色路径的长度。

设当前最长的红色路径长度为 \(dead\),设 \(in_{k,0}\) 表示以 \(k\) 为根的子树内不经过该点的最大直径, \(in_{k,1}\) 表示和 \(in_{k,0}\) 不在同一棵子树里的最大直径,这样向下搜索时如果 \(to\) 是 \(in_{k,0}\) 所在的子树,用 \(in_{k,1}\) 更新 \(dead\),否则用 \(in_{k,0}\) 更新。

另一种情况,如下图:这条红色路径的可以在 \(5\) 号点是更新,具体的,类似换根 DP 的思路,我们记 \(maxn\) 表示当前点向父亲走能走到的最远的距离(树内),用 \(maxn+f_k\) 更新红色路径的长度。但是更新时会出现问题:\(f_5\) 本身由 \(f_6\) 转移而来,所以我们不仅要记录最长根链的长度,还要记录和最长根链不在同一子树内的次长根链的长度,如果 \(f_{to,0}+v_i\) 和 \(f_{k,0}\) 相等,用 \(f_{k,1}+maxn\) 更新红色路径,否则用 \(f_{to,0}\) 更新。

image.png

另另一种情况,如下图:断掉了 \((1,5)\),\(dead\) 还可以由 \(1\) 子树内不经过 \(5\) 的两条链拼接而成,所以我们不仅要记录次大根链,还要记录次次大根链,如果断的边是 \(f_{k,0}\) 的链,用 \(f_{k,1}+f_{k,2}\) 更新 \(dead\),其他情况同理。

image.png

2.直径另一端不在该树内。

这种情况是 trival 的,记录 \(up\) 表示该点到根的距离,每次向下走维护到根的距离的最大值和当前到根的距离,每次还是判断最大次大值与子树的值的关系即可。

细节很多,非常难写。

int n,cnt=1,dead,tot,max2,all,now,now2,maxu,maxi,maxj,ans[800001],pos[800001],id[800001],ide[800001],in[800001][2],f[800001][3],ex[800001],vis[800001],loop[800001],head[800001],to[800001],nex[800001],v[800001],sum[800001],val[800001];
inline void add(int x,int y,int z){to[++cnt]=y,v[cnt]=z,nex[cnt]=head[x],head[x]=cnt;}
stack<int> st;
namespace Segment
{
	struct Node{int maxn,max1,max2,l,l1,r,r2;};
	struct{int l,r;Node nd;}t[3400001];
	Node operator +(const Node nd1,const Node nd2)
	{
		Node nd;nd.l=nd1.l1,nd.r=nd2.r2,nd.maxn=nd1.max1+nd2.max2; 
		if(nd1.maxn>nd.maxn)nd.maxn=nd1.maxn,nd.l=nd1.l,nd.r=nd1.r;
		if(nd2.maxn>nd.maxn)nd.maxn=nd2.maxn,nd.l=nd2.l,nd.r=nd2.r;
		if(nd1.max1>nd2.max1)nd.l1=nd1.l1;else nd.l1=nd2.l1;nd.max1=max(nd1.max1,nd2.max1);
		if(nd1.max2>nd2.max2)nd.r2=nd1.r2;else nd.r2=nd2.r2;nd.max2=max(nd1.max2,nd2.max2);
		return nd;
	}
	void build(int p,int l,int r)
	{
		t[p].l=l,t[p].r=r;
		if(l==r)return t[p].nd.l=t[p].nd.l1=t[p].nd.r=t[p].nd.r2=l,val[l]+=val[l-1],t[p].nd.max2=f[loop[l]][0]+val[l-1],t[p].nd.max1=f[loop[l]][0]-val[l-1],void();
		int mid=l+((r-l)>>1);
		build(p*2,l,mid),build(p*2+1,mid+1,r),t[p].nd=t[p*2].nd+t[p*2+1].nd;
	}
	void change(int p,int x,int y)
	{
		if(t[p].l==t[p].r)return t[p].nd.max2=y+val[x],t[p].nd.max1=y-val[x],void();
		if(x<=t[p*2].r)change(p*2,x,y);else change(p*2+1,x,y);
		t[p].nd=t[p*2].nd+t[p*2+1].nd;
	}
	Node ask(int p,int l,int r)
	{
		if(l<=t[p].l&&r>=t[p].r)return t[p].nd;
		if(l>t[p*2].r)return ask(p*2+1,l,r);
		if(r<=t[p*2].r)return ask(p*2,l,r);
		return ask(p*2,l,r)+ask(p*2+1,l,r);
	}
	void print(int p)
	{
		if(!t[p].l)return;
		write(t[p].l),write(t[p].r),write(t[p].nd.max1),write(t[p].nd.max2),write(t[p].nd.maxn,'\n');
		print(p*2),print(p*2+1);
	}
}
using namespace Segment;
void findloop(int k,int from)
{
	st.e(k);
	for(int i=head[k];i;i=nex[i])
	{
		if(i==(from^1))continue;
		if(sum[to[i]])
		{
			int y;sum[k]=v[i],ide[k]=i;
			do vis[loop[++tot]=y=st.top()]=1,id[tot]=ide[y],val[tot]=sum[y],st.pop();while(y!=to[i]);
		}
		else sum[k]=v[i],ide[k]=i,findloop(to[i],i);
		if(tot)return;
	}
	st.pop();
}
void dfs(int k,int from)
{
	for(int i=head[k];i;i=nex[i])
	{
		if(i==(from^1)||vis[to[i]])continue;
		dfs(to[i],i);int tmp=max(in[to[i]][0],f[to[i]][0]+f[to[i]][1]);
		if(tmp>=in[k][0])in[k][1]=in[k][0],in[k][0]=tmp;
		else if(tmp>=in[k][1])in[k][1]=tmp;
		if(f[to[i]][0]+v[i]>=f[k][0])f[k][2]=f[k][1],f[k][1]=f[k][0],f[k][0]=f[to[i]][0]+v[i];
		else if(f[to[i]][0]+v[i]>=f[k][1])f[k][2]=f[k][1],f[k][1]=f[to[i]][0]+v[i];
		else if(f[to[i]][0]+v[i]>=f[k][2])f[k][2]=f[to[i]][0]+v[i];
	}
}
inline void dfs2(int k,int maxn,int from,int up)
{
	int pre=maxu,ppr=dead;
//		write(k),write(dead,'\n');
	for(int i=head[k],upon;i;i=nex[i])
	{
		if(vis[to[i]]||i==(from^1))continue;
		if(in[to[i]][0]==in[k][0]||f[to[i]][0]+f[to[i]][1]==in[k][0])dead=max(dead,in[k][1]);
		else dead=max(dead,in[k][0]);
//			write(to[i]),write(in[k][0]),write(in[k][1]),write(dead,'\n');
		if(f[to[i]][0]+v[i]==f[k][0])dead=max({dead,f[k][1]+maxn,f[k][1]+f[k][2]});
		else if(f[to[i]][0]+v[i]==f[k][1])dead=max({dead,f[k][0]+maxn,f[k][0]+f[k][2]});
		else dead=max({dead,f[k][0]+f[k][1],maxn+f[k][0]});
//			write(to[i]),write(dead,'\n');
		if(f[to[i]][0]+v[i]==f[k][0])upon=f[k][1],maxu=max(maxu,up+f[k][1]),dfs2(to[i],max(maxn,f[k][1])+v[i],i,up+v[i]);
		else upon=f[k][0],maxu=max(maxu,up+f[k][0]),dfs2(to[i],max(maxn,f[k][0])+v[i],i,up+v[i]);
		ans[pos[i]]=max({dead,in[to[i]][0],f[to[i]][0]+f[to[i]][1],now+max(maxu,upon+up),now2});
		if(f[to[i]][0]+v[i]==f[k][0])ans[pos[i]]=max({ans[pos[i]],f[k][1]+f[k][2],f[k][1]+maxn});
		else if(f[to[i]][0]+v[i]==f[k][1])ans[pos[i]]=max({ans[pos[i]],f[k][0]+f[k][2],f[k][0]+maxn});
		else ans[pos[i]]=max({ans[pos[i]],f[k][0]+f[k][1],f[k][0]+maxn});
		maxu=pre,dead=ppr;
	}
//		write(k),write(dead,'\n');
}
inline Node calc2()
{
	Node nd1,nd2;nd1.maxn=0;
	for(int i=2,j=1;i<=tot*2;++i)
	{
		while((val[i]-val[j])*2>all)++j;
		nd2=ask(1,j,i);if(nd2.maxn>nd1.maxn)nd1=nd2;
	}
	return nd1;
}
inline void calc(int ex)
{
	if(ex>tot)ex-=tot;
	change(1,ex,0),change(1,ex+tot,0),dead=0;
	now=-INF,now2=calc2().maxn;
	for(int i=1;i<=tot;++i)if(i!=ex)now2=max({now2,in[loop[i]][0],f[loop[i]][0]+f[loop[i]][1]});
	for(int i=ex+tot-1;i>ex;--i)if((val[i]-val[ex])*2<=val[tot+1])now=max(now,val[i]+f[loop[i]][0]-val[ex]);
	for(int i=ex+1;i<ex+tot;++i)if((val[ex+tot]-val[i])*2<=val[tot+1])now=max(now,f[loop[i]][0]-val[i]+val[ex+tot]);
	dfs2(loop[ex],0,0,0);
	change(1,ex,f[loop[ex]][0]),change(1,ex+tot,f[loop[ex]][0]);
}
inline void mian()
{
	read(n);int x,y,z,pos2=0;Node nd;
	for(int i=1;i<=n;++i)read(x,y,z),add(x,y,z),add(y,x,z),pos[cnt]=pos[cnt-1]=i;
	findloop(1,0),reverse(loop+1,loop+tot+1),reverse(val+1,val+tot+1),reverse(id+1,id+1+tot),id[0]=id[tot];
	for(int i=1;i<=tot;++i)loop[i+tot]=loop[i],val[i+tot]=val[i],now=i,dfs(loop[i],0),max2=max({max2,in[loop[i]][0],f[loop[i]][0]+f[loop[i]][1]}),max(in[loop[i]][0],f[loop[i]][0]+f[loop[i]][1])==max2?pos2=i:0;
	build(1,1,tot*2),all=val[tot];
	for(int i=tot*2;i>=1;--i)val[i]=val[i-1];
	nd=calc2();
	for(int i=1;i<=tot;++i)ans[pos[id[i-1]]]=max(max2,ask(1,i,i+tot-1).maxn);
	if(nd.maxn<=max2)calc(pos2);else calc(nd.l),calc(nd.r);
	for(int i=1;i<=n;++i)if(!ans[i])write(max(nd.maxn,max2),'\n');else write(ans[i],'\n');
}

标签:int,ddcc2020,nd,dead,ey,maxn,nd1,Pars,nd2
From: https://www.cnblogs.com/WrongAnswer90-home/p/17724582.html

相关文章

  • 算法题——实现类似parseInt的方法
    Scannersc=newScanner(System.in);Stringstr="";while(true){System.out.println("请输入");Stringstr1=sc.nextLine();if(str1.length()<1||str1.length()>10||str1.charAt(0)=='0'){System.out.......
  • macOS Sonoma 14 RC2(23A344)/Ventura13.6/Monterey 12.7 三版系统同时更新
    以下是一篇黑果魏叔关于【macOSSonoma14RC2(23A344)/macOS13.6/macOS12.7同时更新】的文章,希望对您有所帮助。近日,苹果公司发布了macOSSonoma14RC2(23A344)版本更新,这标志着苹果公司继推出macOSBigSur和macOSMonterey之后,再次为macOS系统带来了新的升级。此次升级......
  • CF1467B Hills And Valleys
    修改一座山可能改变其两侧山的类型。贪心地考虑,要么是修改成其左侧山的高度要么是修改成其右侧山的高度,这样能够在使得当前山不成为山峰和山谷的同时让两侧的山尽可能不成为山峰和山谷。如果不在左右两座山高度之间,那一定是山峰或者山谷,修改后肯定不劣。修改第一座山或最后一座山......
  • 【精选视频免费看】Midjourney数字人换脸直播案例分享
    很多学员反馈,课程动辄几十、几百课时的学习时长,难以持续学习;经常课程买了=学了。为此,51CTO学堂在【视频课程】产品基础上,新增【短视频】版块,3分钟聚焦技术精华+个性化推荐内容,实现碎片化技术学习,在这里“随便逛逛,总有新收获”!新功能赶紧一睹为快,一起看看今天都有哪些值得我们IT人......
  • 完美解决TypeError: ‘encoding’ is an invalid keyword argument for this function
    完美解决TypeError:‘encoding’isaninvalidkeywordargumentforthisfunction文章目录报错问题解决方法声明报错问题之前在工作中遇到过这个坑,记录一下问题以及解决方法,不一定针对所有情况都能用,但是可以供大家参考。问题描述如下:TypeError:‘encoding’isaninvalid......
  • 完美解决ParserError: Error tokenizing data. C error: Expected 2 fields in line 5
    完美解决ParserError:Errortokenizingdata.Cerror:Expected2fieldsinline53,saw3文章目录报错问题解决方法声明报错问题之前在工作中遇到过这个坑,记录一下问题以及解决方法,不一定针对所有情况都能用,但是可以供大家参考。问题描述如下:ParserError:Errortokenizing......
  • 已解决ModuleNotFoundError: No module named ‘HTMLParser‘
    已解决ModuleNotFoundError:Nomodulenamed‘HTMLParser’文章目录报错问题解决方法声明报错问题之前在工作中遇到过这个坑,记录一下问题以及解决方法,不一定针对所有情况都能用,但是可以供大家参考。问题描述如下:ModuleNotFoundError:Nomodulenamed‘HTMLParser’python2......
  • react native 使用 KeyboardAvoidingView 无效
    组件介绍:该组件将根据键盘高度自动调整其高度、位置或底部填充,以在显示虚拟键盘时保持可见。官方文档:KeyboardAvoidingView文档地址遇到的问题:KeyboardAvoidingView标签要设置behavior={Platform.OS==="ios"?"padding":"height"},iOS系统要使用padding否则样式可能......
  • macOS Monterey 12.7 (21G816) 正式版 ISO、IPSW、PKG 下载
    macOSMonterey12.7(21G816)正式版ISO、IPSW、PKG下载本站下载的macOS软件包,既可以拖拽到Applications(应用程序)下直接安装,也可以制作启动U盘安装,或者在虚拟机中启动安装。另外也支持在Windows和Linux中创建可引导介质。2023年9月22日,Apple为macOS和iOS......
  • 提高iOS应用程序安全性:使用Keychain和加密技术保护iOS应用程序数据
    ​目录 转载:怎么保护苹果手机移动应用程序ipa中文件安全?前言1.对敏感文件进行文件名称混淆  ​编辑2.更改文件的MD5值3.增加不可见水印处理3.对html,js,css等资源进行压缩5.删除可执行文件中的调试信息 转载:怎么保护苹果手机移动应用程序ipa中文件安全?前......