首页 > 其他分享 >[CTSC2018]暴力写挂题解

[CTSC2018]暴力写挂题解

时间:2023-12-26 22:25:53浏览次数:35  
标签:暴力 fa int 题解 tot dep CTSC2018 cun id

我们先将柿子变成 \(\frac{1}{2}(dis_{x,y}+dep_{x}+dep_{y})-dep'_{lca'}\)

考虑边分治,枚举断边,我们将一个点在第二棵树上的点权看成是 \(v_x=d_x+dep_x\),答案就为 \(v_x+v_y+dep'_{lca'}\)

对于每次边分治将分治联通块内所有点在第二棵树上的建出虚树,同时将分治联通块以分治中心边为界限分成两部分,将一部分的点标为黑点,将另一部分的点标为白点。

那么对于虚树中的一个点,以它为的最大答案就是在它的两个不同子树中分别选出一个黑点和一个白点使这两个点的点权和最大。

我们在虚树上进行树形DP,每个点维护这个点在虚树上的子树中黑点的最大点权及白点的最大点权就行了。

code

#include<bits/stdc++.h>
using namespace std;
#define N 1000005
#define int long long
int n,top,ans=-1e18;
int q[N],val[N],col[N];
namespace XS{
	int k,res,t,tot;
	int h[N],sta[N],id[N],lc[N][20],dep[N],lg[N],vis[N],f[N][2],deep[N];
	vector<int> G[N];
	struct AB{
		int a,b,c,n;
	}d[N*2];
	void cun(int x,int y,int z){
		d[++k]={x,y,z,h[x]},h[x]=k;
	}
	void dfs(int x,int fa){
		lc[++tot][0]=x,id[x]=tot,deep[x]=deep[fa]+1;
		for(int i=h[x];i;i=d[i].n){
			int y=d[i].b;
			if(y==fa) continue;
			dep[y]=dep[x]+d[i].c;
			dfs(y,x),lc[++tot][0]=x;
		}
	}
	int mn(int x,int y){
		return deep[x]<deep[y]?x:y;
	}
	void init(){
		for(int i=1,x,y,z;i<n;i++){
			scanf("%lld%lld%lld",&x,&y,&z);
			cun(x,y,z),cun(y,x,z);
		}
		dfs(1,0);
		for(int i=2;i<=tot;i++) lg[i]=lg[i/2]+1;
		for(int j=1;j<=19;j++){
			for(int i=1;i+(1<<j)-1<=tot;i++) lc[i][j]=mn(lc[i][j-1],lc[i+(1<<(j-1))][j-1]);
		}
	}
	int Lca(int x,int y){
		if(id[x]>id[y]) swap(x,y);
		int p=lg[id[y]-id[x]+1];
		return mn(lc[id[x]][p],lc[id[y]-(1<<p)+1][p]);
	}
	void ins(int x){
		vis[x]=1,G[x].clear();
		if(!t){
			sta[++t]=x;
			return ;
		}
		int lca=Lca(x,sta[t]);
		if(!vis[lca]) col[lca]=-1,G[lca].clear(),vis[lca]=1;
		if(lca!=sta[t]){
			while(t>1&&id[lca]<id[sta[t-1]]) G[sta[t-1]].push_back(sta[t]),t--;
			if(id[lca]!=id[sta[t-1]]) G[lca].push_back(sta[t]),sta[t]=lca;
			else G[lca].push_back(sta[t]),t--;
		}
		sta[++t]=x;
	}
	void DP(int x){
		f[x][0]=f[x][1]=-1e18;
		for(auto y:G[x]){
			DP(y);
			res=max(res,max(f[x][0]+f[y][1],f[x][1]+f[y][0])-2*dep[x]);
			f[x][0]=max(f[x][0],f[y][0]),f[x][1]=max(f[x][1],f[y][1]);
		}
		if(col[x]!=-1) res=max(res,val[x]+f[x][col[x]^1]-2*dep[x]);
		f[x][0]=f[x][1]=-1e18;
		if(col[x]!=-1) f[x][col[x]]=val[x];
		for(int i=G[x].size()-1;~i;i--){
			int y=G[x][i];
			res=max(res,max(f[x][0]+f[y][1],f[x][1]+f[y][0])-2*dep[x]);
			f[x][0]=max(f[x][0],f[y][0]),f[x][1]=max(f[x][1],f[y][1]);
		}
		vis[x]=0;
	}
	bool cmp(int x,int y){
		return id[x]<id[y];
	}
	int work(){
		res=-1e18,t=0;
		sort(q+1,q+1+top,cmp);
		if(q[1]!=1) col[1]=-1,sta[++t]=1,G[1].clear();
		for(int i=1;i<=top;i++) ins(q[i]);
		while(t>1) G[sta[t-1]].push_back(sta[t]),t--;
		DP(1);
		return res;
	}
}
namespace BFZ{
	int k=1,ssz,rt,tot;
	int h[N],dep[N],sz[N],vis[N];
	vector<pair<int,int> > G[N];
	struct AB{
		int a,b,c,n;
	}d[N*2];
	void cun(int x,int y,int z){
		d[++k]={x,y,z,h[x]},h[x]=k;
	}
	void rebuild(int x,int fa){
		int tmp=0,lst=0;
		for(auto p:G[x]){
			int y=p.first,z=p.second;
			if(y==fa) continue;
			tmp++;
			if(tmp==1) cun(x,y,z),cun(y,x,z),lst=x;
			else if(tmp==(int)G[x].size()-(x!=1)) cun(lst,y,z),cun(y,lst,z);
			else tot++,cun(lst,tot,0),cun(tot,lst,0),lst=tot,cun(tot,y,z),cun(y,tot,z);
		}
		for(auto p:G[x]){
			if(p.first==fa) continue;
			rebuild(p.first,x);
		}
	}
	void dfs(int x,int fa){
		for(int i=h[x];i;i=d[i].n){
			int y=d[i].b,z=d[i].c;
			if(y==fa) continue;
			dep[y]=dep[x]+z,dfs(y,x);
		}
	}
	void init(){
		tot=n;
		for(int i=1,x,y,z;i<n;i++){
			scanf("%lld%lld%lld",&x,&y,&z);
			G[x].push_back({y,z}),G[y].push_back({x,z});
		}
		rebuild(1,0);
		dfs(1,0);
	}
	void gt_rt(int x,int fa,int siz){
		sz[x]=1;
		for(int i=h[x];i;i=d[i].n){
			int y=d[i].b;
			if(y==fa||vis[i>>1]) continue;
			gt_rt(y,x,siz),sz[x]+=sz[y];
			int mx_sz=max(siz-sz[y],sz[y]);
			if(mx_sz<ssz) ssz=mx_sz,rt=i;
		}
	}
	void dfs2(int x,int fa,int s,int op){
		if(x<=n) val[x]=s+dep[x],col[x]=op,q[++top]=x;
		for(int i=h[x];i;i=d[i].n){
			int y=d[i].b;
			if(y==fa||vis[i>>1]) continue;
			dfs2(y,x,s+d[i].c,op);
		}
	}
	void solve(int x,int siz){
		ssz=1e9,gt_rt(x,0,siz);
		if(ssz==1e9) return ;
		int i=rt;
		vis[i>>1]=1,top=0;
		dfs2(d[i].a,0,0,0);
		dfs2(d[i].b,0,0,1);
		ans=max(ans,d[i].c+XS::work());
		int sum=sz[d[i].b];
		solve(d[i].a,siz-sum),solve(d[i].b,sum);
	}
}
signed main(){
	scanf("%lld",&n);
	BFZ::init();
	XS::init();
	BFZ::solve(1,BFZ::tot);
	assert(ans%2==0);
	ans/=2;
	for(int i=1;i<=n;i++) ans=max(ans,BFZ::dep[i]-XS::dep[i]);
	printf("%lld\n",ans);
	return 0;
}

标签:暴力,fa,int,题解,tot,dep,CTSC2018,cun,id
From: https://www.cnblogs.com/hubingshan/p/17929490.html

相关文章

  • CF1887D Split 题解
    Problem-D-CodeforcesSplit-洛谷我现在水平好烂,再做下去自信心就全败没了先考虑\(Q=1\)怎么做?两种做法:暴力枚举分界点,左右判断暴力枚举\(\max\limits_{i=l}^{x}a_i\),找到最靠右边的分界点位置\(x\),判断是否\(\max\limits_{i=l}^{x}a_i<\min\limits......
  • [ABC267F] Exactly K Steps 题解
    [ABC267F]ExactlyKSteps题解思路首先发现,如果对于查询\((u,k),k>0\)可行,那么对于\((u,k-1)\)也一定可行,因为往回走一步就可以了,所以对于一个点可以找到离它最远的点,根据直径的结论,这个点一定是直径的端点之一。为了方便做,以直径的端点之一为根,然后写一个K级祖......
  • 【CF30E】Tricky and Clever Password 题解(manacher + exKMP)
    manacher+exKMP+二分。感觉是最粗暴的方法,想出来之后自己硬莽了4k,荣获题解区最长。Solution约定:下文所提及到的所有的回文串,均指奇长度回文串。显然把题目拆成两个部分,中间的回文串,以及两边相同的连续子串。考虑一下从哪个入手比较好。忘记是咋想的了,易得从两边相同......
  • [SNOI2019] 网络 题解
    [SNOI2019]网络题解最喜欢这道题。简要题意给一颗\(n\)个节点的树和一个参数\(d\),定义两个节点\(x,y\)之间的距离为\(x\)到\(y\)的简单路径上的边数。定义一个树上连通块的权值为连通块中任意两点的距离之和。定义一个树上连通块的直径为连通块中任意两点距离的最......
  • CF1887C Minimum Array 题解
    Problem-1887C-CodeforcesMinimumArray-洛谷有点被降智了/ll首先区间修改显然先转化成差分序列单点修改。显然对于相同的操作序列,\(a_i\)的取值对答案无影响,因此我们可以先让\(a_i\)全部取\(0\),最后再加回来即可假如说操作到某一时刻,\(a_i\)的值中第一个......
  • 洛谷B3647 【模板】Floyd 题解 floyd算法 求 多源多汇最短路
    题目链接:https://www.luogu.com.cn/problem/B3647floyd算法:https://oi-wiki.org/graph/shortest-path/#floyd-算法示例程序:#include<bits/stdc++.h>usingnamespacestd;constintmaxn=101;intn,m,f[maxn][maxn];intmain(){scanf("%d%d",&n......
  • [题解]CF1811D Umka and a Long Flight
    思路假设原题目中的\(n\)在本文中为\(num\),则原长方形的长\(m=f_{num+1}\)和宽\(n=f_{num}\)。显然对于最初始的长方形,显然是要将一个\(f_{num}\timesf_{num}\)的长方形丢进去的,并且要么放最左边,要么放在最右边。因为对于当前的\(m=f_{num+1}=f_{num}+......
  • CF768G The Winds of Winter题解
    我们考虑暴力咋做,每次得到一个森林之后,必定是从最大的树上摘一棵子树,挪到最小的树上,所以此时的答案为\(max(siz_{mx}-x,siz_{mn}+x,siz_{次大值})\),于是发现\(x=\frac{siz_{mx}-siz_{mn}}{2}\)时答案最优,所以只需找到这个值的前驱后继即可我们使用\(\text{multiset}\)实现,......
  • HNOI2017影魔题解
    HNOI2017影魔对于两种贡献,都只用考虑左边第一个比自己大的,和右边第一个比自己大的数,分别记为\(l_i、r_i\)对于询问一,每个数对\((l_i,r_i)\)构成全部情况对于询问二,可以拆分成\(x=l_i\)时,\(y\in[i+1,r_i-1]\),以及\(y=r_i\)时,\(x\in[l_i+1,i-1]\)我们考虑用扫描线......
  • 软件测试/测试开发|selenium NoSuchDriverException问题解决
    前言我们在使用selenium进行web自动化测试时,有时候会遇到NoSuchDriverException的问题,这个异常通常是由于WebDriver无法找到指定的浏览器驱动而引起的。在这篇文章中,我们将讨论NoSuchDriverException的原因以及如何解决这个问题。NoSuchDriverException是什么?NoSuchDriverExce......