[CF980F]Cactus to Tree

Posted Tan_tan_tann

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[CF980F]Cactus to Tree相关的知识,希望对你有一定的参考价值。

Cactus to Tree

题解

换根dp板子

首先看到这种求出每个节点到叶节点上的最大距离值最小,很容易想到换根。
我们考虑对于一个节点,他什么时候在图上可以使得叶节点与它的距离最小。
很明显对于任意节点,它到其他节点的最短路是不冲突的,我们在这个图上建出它的 b f s bfs bfs树时一定是最小的,相当于我们要在这个图上再到这个点到其他所有点最短路的最大值。
由于这图保证每个点属于且仅属于一个环,所以它大概是长这样的:
在这里插入图片描述
我们可以先以某个点为根,求出每个点到它环外的子树 (其实就是再往下的部分) 上的点的距离最大值。
再对原树进行缩点,将一个环缩成一个点,进行换根。

当换根到某个点时,我们可以将它所属环上的所有点的答案一并求出。
对于这环上的每个点,先暴力枚举其儿子,求出其到它的环外子树中叶节点的距离最大值,再考虑环上点的贡献。
g i g_{i} gi表示点 i i i的环外子树中叶节点的距离最大值,很明显有,
a n s i = max ⁡ j ∈ V ( g v + d i s t i , j ) ans_{i}=\\max_{j\\in V}\\left(g_{v}+dist_{i,j}\\right) ansi=jVmax(gv+disti,j)
由于 d i s t dist dist在环上分为两段递增,往左往右都是递增,直到环的另一侧与其相对应的点为止。
所以我们可以考虑用单调队列维护环上的点的答案转移。

从一个环换到另一个环时,我们只需要将两环之间桥上在原环上的对应点求出最大值与次大值,看应该去哪一个即可。
注意不能光求子树上的距离,还要注意环上的距离,通过之前求的 a n s ans ans也就可以得知环上的最大值了。

时间复杂度 O ( n + m ) O\\left(n+m\\right) O(n+m)
不过笔者求环上点时是跟据dfs序排序得到的,所以还要加上一个 l o g log log
虽然题目并没有给 m m m的范围,但由于一个点只属于一个环可知 m ⩽ 3 2 n m\\leqslant \\frac{3}{2}n m23n,也就是 n 2 \\frac{n}{2} 2n个二元环构成链是取最大值。

源码

#include<bits/stdc++.h>
using namespace std;
#define MAXN 500005
#define lowbit(x) (x&-x)
#define reg register
#define pb push_back
#define mkpr make_pair
#define fir first
#define sec second
#define lson (rt<<1)
#define rson (rt<<1|1)
typedef long long LL;
typedef unsigned long long uLL;
const int INF=0x3f3f3f3f;
const int mo=998244353;
const int inv2=499122177;
const int jzm=2333;
const int orG=3,invG=332748118;
const int lim=300000;
const double Pi=acos(-1.0);
typedef pair<int,int> pii;
const double PI=acos(-1.0);
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
template<typename _T>
void read(_T &x){
	_T f=1;x=0;char s=getchar();
	while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
	while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
	x*=f;
}
template<typename _T>
void print(_T x){if(x<0){x=(~x)+1;putchar('-');}if(x>9)print(x/10);putchar(x%10+'0');}
int gcd(int a,int b){return !b?a:gcd(b,a%b);}
int add(int x,int y){return x+y<mo?x+y:x+y-mo;}
int qkpow(int a,int s){int t=1;while(s){if(s&1)t=1ll*a*t%mo;a=1ll*a*a%mo;s>>=1;}return t;}
int n,m,head[MAXN],tot,dp[MAXN],g[MAXN],dfn[MAXN],low[MAXN],belong[MAXN];
int sta[MAXN],stak,idx,cnt,q[2][MAXN<<1],Head[2],Tail[2],ans[MAXN];
int dis[MAXN],ord[MAXN],tid,mxd[MAXN];
bool vis[MAXN];
vector<int>cir[MAXN]; 
queue<int>Q;
struct edge{int to,nxt;}e[MAXN*3];
void addEdge(int u,int v){e[++tot]=(edge){v,head[u]};head[u]=tot;}
void bfs(int s){
	while(!Q.empty())Q.pop();Q.push(s);dis[s]=1;vis[s]=1;
	while(!Q.empty()){
		int t=Q.front();Q.pop();ord[++tid]=t;
		for(int i=head[t];i;i=e[i].nxt){
			int v=e[i].to;if(vis[v])continue;
			Q.push(v);vis[v]=1;dis[v]=dis[t]+1;
		}
	}
	for(int i=tid;i>0;i--){
		int u=ord[i];mxd[u]=dis[u];
		for(int j=head[u];j;j=e[j].nxt)
			mxd[u]=max(mxd[e[j].to],mxd[u]);
		dp[u]=mxd[u]-dis[u]+1;
	}
}
void tarjan(int u,int fa){
	dfn[u]=low[u]=++idx;sta[++stak]=u;
	for(int i=head[u];i;i=e[i].nxt){
		int v=e[i].to;
		if(!dfn[v])tarjan(v,u),low[u]=min(low[u],low[v]);
		else if(v!=fa)low[u]=min(low[u],dfn[v]);
	}
	if(low[u]==dfn[u]){++cnt;int v;do{v=sta[stak--];belong[v]=cnt;}while(v!=u);}
} 
void dosaka(int u,int fa){
	int id=belong[u],siz=cir[id].size();Head[0]=Tail[0]=Head[1]=Tail[1]=1;
	for(int i=0;i<siz;i++){
		g[i]=1;
		for(int j=head[cir[id][i]];j;j=e[j].nxt)
			if(belong[e[j].to]!=id)g[i]=max(dp[e[j].to]+1,g[i]);
	}
	for(int i=1;i+i<=siz;i++){
		while(Head[0]<Tail[0]&&g[i]+i>=g[q[0][Tail[0]-1]]+q[0][Tail[0]-1])Tail[0]--;
		q[0][Tail[0]++]=i;
	}
	for(int i=(siz+1)/2;i<siz;i++){
		while(Head[1]<Tail[1]&&g[i]-i>=g[q[1][Tail[1]-1]]-q[1][Tail[1]-1])Tail[1]--;
		q[1][Tail[1]++]=i;
	}
	if(Head[0]<Tail[0])ans[u]=max(ans[u],g[q[0][Head[0]]]+q[0][Head[0]]);
	if(Head[1]<Tail[1])ans[u]=max(ans[u],g[q[1][Head[1]]]+siz-q[1][Head[1]]);
	for(int i=1;i<siz;i++){
		int stp=cir[id][i],las=i-1,lst=(i+(siz+1)/2-1+siz)%siz;
		while(Head[1]<Tail[1]&&q[1][Head[1]]==lst)Head[1]++;
		while(Head[0]<Tail[0]&&q[0][Head[0]]==i)Head[0]++;
		while(Head[1]<Tail[1]&&g[q[1][Tail[1]-1]]+(i+siz-q[1][Tail[1]-1])%siz<=g[las]+(i+siz-las)%siz)Tail[1]--;q[1][Tail[以上是关于[CF980F]Cactus to Tree的主要内容,如果未能解决你的问题,请参考以下文章

构造题 贪心cf1041E. Tree Reconstruction

cf codeforces round#527F. Tree with Maximum Cost树形dp

CF#468 div2 D. Peculiar apple-tree(思维)

CF Round #722 (Div. 2) C. Parsa‘s Humongous Tree(树形dp)

bzoj千题计划224:bzoj1023: [SHOI2008]cactus仙人掌图

CF570D:Tree Requests