[Apio2010]patrol 巡逻

<body> <center><h1>1912: [Apio2010]patrol 巡逻</h1><span class="green">Time Limit: </span>4 Sec&nbsp;&nbsp;<span class="green">Memory Limit: </span>64 MB<br><span class="green">Submit: </span>2541&nbsp;&nbsp;<span class="green">Solved: </span>1288<br>[<a href="submitpage.php?id=1912">Submit</a>][<a href="problemstatus.php?id=1912">Status</a>][<a href="bbs.php?id=1912">Discuss</a>]</center><h2>Description</h2><div class="content"><img border="0" src="https://www.lydsy.com/JudgeOnline/images/1912_1.jpg"> </div><h2>Input</h2><div class="content">第一行包含两个整数 n, K(1 ≤ K ≤ 2)。接下来 n – 1行,每行两个整数 a, b, 表示村庄a与b之间有一条道路(1 ≤ a, b ≤ n)。 </div><h2>Output</h2><div class="content">输出一个整数,表示新建了K 条道路后能达到的最小巡逻距离。 </div><h2>Sample Input</h2> <div class="content"><span class="sampledata">8 1 <br> 1 2 <br> 3 1 <br> 3 4 <br> 5 3 <br> 7 5 <br> 8 5 <br> 5 6 </span></div><h2>Sample Output</h2> <div class="content"><span class="sampledata">11</span></div><h2>HINT</h2> <div class="content"><p>10%的数据中,n ≤ 1000, K = 1; <br> 30%的数据中,K = 1; <br> 80%的数据中,每个村庄相邻的村庄数不超过 25; <br> 90%的数据中,每个村庄相邻的村庄数不超过 150; <br> 100%的数据中,3 ≤ n ≤ 100,000, 1 ≤ K ≤ 2。 </p></div><h2>Source</h2> <div class="content"><p><a href="problemset.php?search="></a></p></div><center>[<a href="submitpage.php?id=1912">Submit</a>][<a href="problemstatus.php?id=1912">Status</a>][<a href="bbs.php?id=1912">Discuss</a>]</center><br> <a href="./"><span class="red">HOME</span></a> <a href="javascript:history.go(-1)"><span class="red">Back</span></a> <hr> </body>

题解

参照AntiQuality的题解。

k=0

不过首先挖掘性质:显然的是,若只是树形图,路径最短为2n−2;并且实际上起点任意对于答案来说都是一样的

k=1

然后我们来想一想k=1的情况。比如现在我们有一颗树长成这样:

然后我们现在添加一条边:

可以发现形成的环上,若环长度为lens,那么需要经过的路径就从2∗lens变为了lens+1。并且对于其他节点来说,它们的花费是不改变的。
由此自然想到我们将最长链的首尾相连,就可以得到k=1时的答案。

k=2

有了k=1,扩展至k=2的思路大致相同。除了最长链形成的环,我们需要在树上另找一条次长链。
这里有一个技巧就是把最长链上的边权全都改为-1
如果我们什么处理都没有,直接求一个次长链(次短路方法), 可能会和最长链重合,那么最长链上的一部分就会走两遍
所以我们在求出最长链之后,把最长链上的边权赋为-1, 这样再跑一个裸的直径就好了 (这样就可以保证可以在新求出的直径中尽量少重合原先的直径)

时间复杂度\(O(n)\)

#include<bits/stdc++.h>
#define rg register
#define il inline
#define co const
template<class T>il T read(){
    rg T data=0,w=1;rg char ch=getchar();
    for(;!isdigit(ch);ch=getchar())if(ch=='-') w=-w;
    for(;isdigit(ch);ch=getchar()) data=data*10+ch-'0';
    return data*w;
}
template<class T>il T read(rg T&x) {return x=read<T>();}
typedef long long ll;
using namespace std;

co int N=1e5+6;
int n,k,d[N],fa[N];
int Head[N],Edge[N*2],Leng[N*2],Next[N*2],tot=1;
bool v[N];
void add(int x,int y,int z){
	Edge[++tot]=y,Leng[tot]=z,Next[tot]=Head[x],Head[x]=tot;
}
void dfs(int x,int&t){
	v[x]=1;
	for(int i=Head[x],y;i;i=Next[i]){
		if(v[y=Edge[i]]) continue;
		if((d[y]=d[x]+Leng[i])>=d[t]) t=y;
		fa[y]=i;
		dfs(y,t);
	}
	v[x]=0;
}
void dp(int x,int&t){
	v[x]=1;
	for(int i=Head[x],y;i;i=Next[i]){
		if(v[y=Edge[i]]) continue;
		dp(y,t);
		t=max(t,d[x]+d[y]+Leng[i]);
		d[x]=max(d[x],d[y]+Leng[i]);
	}
	v[x]=0;
}
int main(){
	read(n),read(k);
	for(int i=1,x,y;i<n;++i){
		read(x),read(y);
		add(x,y,1),add(y,x,1);
	}
	int t=1;
	dfs(1,t);
	d[t]=fa[t]=0;
	int tt=t;
	dfs(t,tt);
	int ans=2*(n-1)-(d[tt]-1);
	if(k==2){
		while(fa[tt]){
			Leng[fa[tt]]=Leng[fa[tt]^1]=-1;
			tt=Edge[fa[tt]^1];
		}
		tt=0;
		memset(d,0,sizeof d);
		dp(t,tt);
		ans-=tt-1;
	}
	printf("%d\n",ans);
	return 0;
}

posted on 2019-05-25 12:46  autoint  阅读(146)  评论(0编辑  收藏  举报

导航