Codeforces 980F Cactus to Tree 仙人掌 Tarjan 树形dp 单调队列

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

题目传送门 - CF980F

题意

  给定一个 $n$ 个节点 $m$ 条长为 $1$ 的边的仙人掌。

  现在请你通过删边把仙人掌转化成树。

  对于每一个点,输出在所有不同的删边方案中,  距离该点最远的点与他之间的距离值 的最小值。

  $n\leq 5\times 10^5$

题解

  

代码

#include <bits/stdc++.h>
#pragma comment(linker, "/STACK:102400000,102400000") 
using namespace std;
const int N=500005,M=N*4;
struct Gragh{
	//2M*2*4B+0.5M*4B=18MB
	int cnt,y[M],nxt[M],fst[N];
	void clear(){
		cnt=1;
		memset(fst,0,sizeof fst);
	}
	void add(int a,int b){
		y[++cnt]=b,nxt[cnt]=fst[a],fst[a]=cnt;
	}
}g,g2;
int n,m;
int dfn[N],low[N],inst[N],st[N],vis[N],id[N],Time,top,tot;
int used[M];
int Fa[N];
vector <int> cir[N],son[N];
void Tarjan_Prepare(){
	Time=top=tot=0;
	memset(id,0,sizeof id);
	memset(st,0,sizeof st);
	memset(dfn,0,sizeof dfn);
	memset(low,0,sizeof low);
	memset(vis,0,sizeof vis);
	memset(inst,0,sizeof inst);
	memset(used,0,sizeof used);
}
void Tarjan(int x){
	dfn[x]=low[x]=++Time;
	vis[x]=inst[x]=1;
	st[++top]=x;
	for (int i=g.fst[x];i;i=g.nxt[i]){
		if (used[i/2])
			continue;
		used[i/2]=1;
		if (!vis[g.y[i]]){
			Tarjan(g.y[i]);
			low[x]=min(low[x],low[g.y[i]]);
		}
		else if (inst[g.y[i]])
			low[x]=min(low[x],low[g.y[i]]);
	}
	if (dfn[x]==low[x]){
		tot++;
		id[st[top]]=tot;
		inst[st[top]]=0;
		while (st[top--]!=x){
			id[st[top]]=tot;
			inst[st[top]]=0;
		}
	}
}
void Get_cir(int x){
	if (vis[x])
		return;
	vis[x]=1;
	cir[id[x]].push_back(x);
	for (int i=g.fst[x];i;i=g.nxt[i]){
		int y=g.y[i];
		if (id[y]==id[x])
			Get_cir(y);
	}
}
void build(int x,int pre){
	int ID=id[x];
	Fa[ID]=pre;
	cir[ID].clear();
	Get_cir(x);
	for (int i=0;i<cir[ID].size();i++){
		int u=cir[ID][i];
		son[u].clear();
		for (int j=g.fst[u];j;j=g.nxt[j]){
			int v=g.y[j];
			if (id[v]==ID||id[v]==pre)
				continue;
			son[u].push_back(v);
			build(v,ID);
		}
	}
}
int Deep[N];
// The Minimum value of the distance between 
// x and the deepest posterity of x 
// 环根:   以该环为根的子树中,距离 x 最远的点与其距离的 最小值 
// 非环根: 该节点所有子节点(显然都是环根)的 Deep 最大值 + 1 
int spDeep[N],usDeep[N];
// spDeep[x] x 为环根,环边节点给他的贡献 
// usDeep[x] x 为环根,桥边子树给他的贡献 
int Lmax[N],Rmax[N];
void Get_Deep(int x){
	int ID=id[x];
	for (int i=0;i<cir[ID].size();i++){
		int u=cir[ID][i],v;
		Deep[u]=0;
		for (int j=0;j<son[u].size();j++){
			v=son[u][j];
			Get_Deep(v);
			Deep[u]=max(Deep[u],Deep[v]+1);
		}
	}
	int n=cir[ID].size()-1;
	Lmax[0]=Rmax[n+1]=0;
	for (int i=1;i<=n;i++)
		Lmax[i]=max(Lmax[i-1],Deep[cir[ID][i]]+i);
	for (int i=n;i>=1;i--)
		Rmax[i]=max(Rmax[i+1],Deep[cir[ID][i]]+(n-i+1));
	int v=1e9;
	for (int i=1;i<=n+1;i++)
		v=min(v,max(Lmax[i-1],Rmax[i]));
	Deep[x]=max(usDeep[x]=Deep[x],spDeep[x]=v);
}
int Far[N];
// The Minimum value of the distance between 
// x and the farthest vetrex which isn't a posterity of x 
// 环根:    由其父亲继承 
// 非环根:  环内单调队列跑出来 
int val[N*3];
int Lv[N*3],Rv[N*3];
struct Monotone_Queue{
	int head,tail,q[N*3],d[N*3];
	void clear(){
		head=1,tail=0;
	}
	int front(){
		return head<=tail?q[head]:-1e9;
	}
	void push(int v,int _d){
		while (head<=tail&&q[tail]<=v)
			tail--;
		q[++tail]=v,d[tail]=_d;
	}
	void pop(int _d){
		while (head<=tail&&d[head]<_d)
			head++;
	}
	int Next_front(int _d){
		if (head>tail)
			return -1e9;
		if (d[head]!=_d)
			return q[head];
		return head==tail?-1e9:q[head+1];
	}
}QL,QR;
vector <int> LRmax[N];
void Solve(int x,int far){
	int ID=id[x];
	Far[x]=far;
	int n=cir[ID].size();
	for (int i=1;i<n;i++)
		val[i]=Deep[cir[ID][i]];
	val[0]=max(usDeep[x],Far[x]);
	for (int i=n;i<n*3;i++)
		val[i]=val[i%n];
	for (int i=0;i<n*3;i++){
		Lv[i]=val[i]+n*3-i;
		Rv[i]=val[i]+i+1;
	}
	QL.clear(),QR.clear();
	int Lp=2,Rp=n+1;
	for (int i=Lp;i<=n;i++)
		QL.push(Lv[i],i);
	for (int i=n+1;i<n*2;i++){
		int result=1e9;
		int v1=n*3-i,v2=i+1;
		while (Rp<i){
			Lp++,QL.pop(Lp);
			Rp++;
			if (Rp!=i)
				QR.push(Rv[Rp],Rp);
		}
		while (QL.Next_front(Lp)-v1>max(QR.front(),Rv[Rp+1])-v2){
			result=min(result,QL.front()-v1);
			Lp++,QL.pop(Lp);
			Rp++,QR.push(Rv[Rp],Rp);
		}
		result=min(result,QL.front()-v1);
		result=min(result,max(QR.front(),Rv[Rp+1])-v2);
		QL.push(Lv[i],i);
		QR.pop(i+2);
		Far[cir[ID][i%n]]=result;
	}
	for (int i=0;i<n;i++){
		int u=cir[ID][i];
		int m=son[u].size();
		Lmax[0]=Rmax[m+1]=0;
		for (int j=1;j<=m;j++)
			Lmax[j]=max(Lmax[j-1],Deep[son[u][j-1]]+1);
		for (int j=m;j>=1;j--)
			Rmax[j]=max(Rmax[j+1],Deep[son[u][j-1]]+1);
		LRmax[u].clear();
		for (int j=0;j<m;j++)
			LRmax[u].push_back(max(Lmax[j],Rmax[j+2]));
		for (int j=0;j<m;j++)
			Solve(son[u][j],max(spDeep[u],max(Far[u],LRmax[u][j]))+1);
	}
}
int main(){
	scanf("%d%d",&n,&m);
	g.clear();
	for (int i=1,a,b;i<=m;i++){
		scanf("%d%d",&a,&b);
		g.add(a,b);
		g.add(b,a);
	}
	Tarjan_Prepare();
	for (int i=1;i<=n;i++)
		if (!vis[i])
			Tarjan(i);
	memset(vis,0,sizeof vis);
	build(1,0);
	Get_Deep(1);
	Solve(1,0);
	for (int i=1;i<=n;i++)
		printf("%d ",max(Far[i],Deep[i]));
	return 0;
}

  

再放一份打满调试语句的代码:

#include <bits/stdc++.h>
#pragma comment(linker, "/STACK:102400000,102400000") 
using namespace std;
const int N=500005,M=N*4;
struct Gragh{
	//2M*2*4B+0.5M*4B=18MB
	int cnt,y[M],nxt[M],fst[N];
	void clear(){
		cnt=1;
		memset(fst,0,sizeof fst);
	}
	void add(int a,int b){
		y[++cnt]=b,nxt[cnt]=fst[a],fst[a]=cnt;
	}
}g,g2;
int n,m;
int dfn[N],low[N],inst[N],st[N],vis[N],id[N],Time,top,tot;
int used[M];
int Fa[N];
vector <int> cir[N],son[N];
void Tarjan_Prepare(){
	Time=top=tot=0;
	memset(id,0,sizeof id);
	memset(st,0,sizeof st);
	memset(dfn,0,sizeof dfn);
	memset(low,0,sizeof low);
	memset(vis,0,sizeof vis);
	memset(inst,0,sizeof inst);
	memset(used,0,sizeof used);
}
void Tarjan(int x){
	dfn[x]=low[x]=++Time;
	vis[x]=inst[x]=1;
	st[++top]=x;
	for (int i=g.fst[x];i;i=g.nxt[i]){
		if (used[i/2])
			continue;
		used[i/2]=1;
		if (!vis[g.y[i]]){
			Tarjan(g.y[i]);
			low[x]=min(low[x],low[g.y[i]]);
		}
		else if (inst[g.y[i]])
			low[x]=min(low[x],low[g.y[i]]);
	}
	if (dfn[x]==low[x]){
		tot++;
		id[st[top]]=tot;
		inst[st[top]]=0;
		while (st[top--]!=x){
			id[st[top]]=tot;
			inst[st[top]]=0;
		}
	}
}
void Get_cir(int x){
	if (vis[x])
		return;
	vis[x]=1;
	cir[id[x]].push_back(x);
	for (int i=g.fst[x];i;i=g.nxt[i]){
		int y=g.y[i];
		if (id[y]==id[x])
			Get_cir(y);
	}
}
void build(int x,int pre){
	int ID=id[x];
	Fa[ID]=pre;
	cir[ID].clear();
	Get_cir(x);
	for (int i=0;i<cir[ID].size();i++){
		int u=cir[ID][i];
		son[u].clear();
		for (int j=g.fst[u];j;j=g.nxt[j]){
			int v=g.y[j];
			if (id[v]==ID||id[v]==pre)
				continue;
			son[u].push_back(v);
			build(v,ID);
		}
	}
}
int Deep[N];
// The Minimum value of the distance between 
// x and the deepest posterity of x 
// 环根:   以该环为根的子树中,距离 x 最远的点与其距离的 最小值 
// 非环根: 该节点所有子节点(显然都是环根)的 Deep 最大值 + 1 
int spDeep[N],usDeep[N];
// spDeep[x] x 为环根,环边节点给他的贡献 
// usDeep[x] x 为环根,桥边子树给他的贡献 
int Lmax[N],Rmax[N];
void Get_Deep(int x){
	int ID=id[x];
	for (int i=0;i<cir[ID].size();i++){
		int u=cir[ID][i],v;
		Deep[u]=0;
		for (int j=0;j<son[u].size();j++){
			v=son[u][j];
			Get_Deep(v);
			Deep[u]=max(Deep[u],Deep[v]+1);
		}
	}
	int n=cir[ID].size()-1;
	Lmax[0]=Rmax[n+1]=0;
	for (int i=1;i<=n;i++)
		Lmax[i]=max(Lmax[i-1],Deep[cir[ID][i]]+i);
	for (int i=n;i>=1;i--)
		Rmax[i]=max(Rmax[i+1],Deep[cir[ID][i]]+(n-i+1));
	int v=1e9;
	for (int i=1;i<=n+1;i++)
		v=min(v,max(Lmax[i-1],Rmax[i]));
	Deep[x]=max(usDeep[x]=Deep[x],spDeep[x]=v);
}
int Far[N];
// The Minimum value of the distance between 
// x and the farthest vetrex which isn't a posterity of x 
// 环根:    由其父亲继承 
// 非环根:  环内单调队列跑出来 
int val[N*3];
int Lv[N*3],Rv[N*3];
struct Monotone_Queue{
	int head,tail,q[N*3],d[N*3];
	void clear(){
		head=1,tail=0;
	}
	int front(){
		return head<=tail?q[head]:-1e9;
	}
	void push(int v,int _d){
		while (head<=tail&&q[tail]<=v)
			tail--;
		q[++tail]=v,d[tail]=_d;
	}
	void pop(int _d){
		while (head<=tail&&d[head]<_d)
			head++;
	}
	int Next_front(int _d){
		if (head>tail)
			return -1e9;
		if (d[head]!=_d)
			return q[head];
		return head==tail?-1e9:q[head+1];
	}
	void print(){
		printf("size=%d, sit=:",tail-head+1);
		for (int i=head;i<=tail;i++)
			printf("(%d,%d)  ",q[i],d[i]);
		puts("");
	}
}QL,QR;
vector <int> LRmax[N];
void Solve(int x,int far){
	int ID=id[x];
	Far[x]=far;
	int n=cir[ID].size();
	for (int i=1;i<n;i++)
		val[i]=Deep[cir[ID][i]];
	val[0]=max(usDeep[x],Far[x]);
	for (int i=n;i<n*3;i++)
		val[i]=val[i%n];
	for (int i=0;i<n*3;i++){
		Lv[i]=val[i]+n*3-i;
		Rv[i]=val[i]+i+1;
	}
//	for (int i=0;i<n*3;i++)
//		printf("==>%d %d(%d) %d(%d)\n",val[i],Lv[i],n*3-i,Rv[i],i+1);
	QL.clear(),QR.clear();
	int Lp=2,Rp=n+1;
	for (int i=Lp;i<=n;i++)
		QL.push(Lv[i],i);
	for (int i=n+1;i<n*2;i++){
		int result=1e9;
		int v1=n*3-i,v2=i+1;
//		printf("i=%d,v1=%d,v2=%d\n",i,v1,v2);
		while (Rp<i){
			Lp++,QL.pop(Lp);
			Rp++;
			if (Rp!=i)
				QR.push(Rv[Rp],Rp);
		}
//		printf("x=%d,i=%d,Lp=%d,Rp=%d,Q=..(L,R)\n",x,i,Lp,Rp);QL.print(),QR.print();
		while (QL.Next_front(Lp)-v1>max(QR.front(),Rv[Rp+1])-v2){
			result=min(result,QL.front()-v1);
			Lp++,QL.pop(Lp);
			Rp++,QR.push(Rv[Rp],Rp);
		}
//		printf("x=%d,i=%d,Lp=%d,Rp=%d,Q=..(L,R)\n",x,i,Lp,Rp);QL.print(),QR.print();
		result=min(result,QL.front()-v1);
		result=min(result,max(QR.front(),Rv[Rp+1])-v2);
		QL.push(Lv[i],i);
		QR.pop(i+2);
		Far[cir[ID][i%n]]=result;
	}
	for (int i=0;i<n;i++){
		int u=cir[ID][i];
		int m=son[u].size();
		Lmax[0]=Rmax[m+1]=0;
		for (int j=1;j<=m;j++)
			Lmax[j]=max(Lmax[j-1],Deep[son[u][j-1]]+1);
		for (int j=m;j>=1;j--)
			Rmax[j]=max(Rmax[j+1],Deep[son[u][j-1]]+1);
/*		printf("u=%d,son=:",u);
		for (int j=0;j<m;j++)
			printf("%d ",son[u][j]);
		for (int i=1;i<=m;i++)
			printf ("(%d,%d) ",Lmax[i],Rmax[i]);puts("");*/
		LRmax[u].clear();
		for (int j=0;j<m;j++)
			LRmax[u].push_back(max(Lmax[j],Rmax[j+2]));
		for (int j=0;j<m;j++)
			Solve(son[u][j],max(spDeep[u],max(Far[u],LRmax[u][j]))+1);
	}
}
int main(){
	scanf("%d%d",&n,&m);
	g.clear();
	for (int i=1,a,b;i<=m;i++){
		scanf("%d%d",&a,&b);
		g.add(a,b);
		g.add(b,a);
	}
	Tarjan_Prepare();
	for (int i=1;i<=n;i++)
		if (!vis[i])
			Tarjan(i);
	memset(vis,0,sizeof vis);
//	for (int i=1;i<=n;i++)
//		printf("%d: %d\n",i,id[i]);
	build(1,0);
	Get_Deep(1);
	Solve(1,0);
/*	for (int i=1;i<=tot;i++,puts(""))
		for (int j=0;j<cir[i].size();j++)
			printf("%d ",cir[i][j]);*/
/*	for (int i=1;i<=n;i++){
		printf("%d:",i);
		for (int j=0;j<son[i].size();j++)
			printf(" %d",son[i][j]);
		puts("");
	}*/
/*	for (int i=1;i<=n;i++)
		printf("%d: %d %d %d %d\n",i,Deep[i],spDeep[i],usDeep[i],Far[i]);*/
	for (int i=1;i<=n;i++)
		printf("%d ",max(Far[i],Deep[i]));
	return 0;
}

  

猜你喜欢

转载自www.cnblogs.com/zhouzhendong/p/CF980F.html
今日推荐