【NOI.AC R5T3能量树】机智的树论问题

(祝大家中秋节快乐!"但愿人长久,千里共婵娟。“希望世界依然美好,珍惜好仍然的存在! by 2018/09/24) 对于树论问题,我宛若一个ZZ

能量树(power)

题目描述

小D梦见了一棵包含$n$个节点的树,这棵树包含着神秘的能量。具体来讲,对于这棵树中的一个联通块,它的能量为它拥有的节点中编号连续的最长的一段。举例来说,如果一个连通块包含了原树中编号为$\{1,3,4,5,7,8\}$的节点,那么编号连续的最长的一段为$\{3,4,5\}$。它所具有的能量值为$3$。 小D想要从这棵树中获得能量,但由于种种原因,小D只能从这棵树中选取一个节点数不大于$k$的连通块并获得它的能量值,小D想要知道他能取得的最大能量值是多少。 一棵树包含$n$个节点的树就是有$n$个点,$n-1$条边的连通图。

输入格式

第一行两个正整数$n$,$k$,分别表示树的大小,选取的子树允许的最大大小。 第二行到第$n$行,每行两个正整数$u$,$v$,表示树上有一条连接节点$u$和节点$v$的边。

输出格式

一行一个整数,表示选取的子树的能量的最大值。

样例

input1

10 6
4 10
10 6
2 9
9 6
8 5
7 1
4 7
7 3
1 8

output1

3

explanation

选择的联通块节点编号为$\{1,3,4,5,7,8\}$或$\{1,4,6,7,8,10\}$都包含$3$个编号连续的顶点。没有节点数大于$6$的连通块包含大于$3$个编号连续的顶点。

input2

见ex_power2.in。

output2

见ex_power2.ans。

数据范围和约定

对于$10\%$的数据,$n\le20$。 对于$20\%$的数据,$n\le200$。 对于$40\%$的数据,$n\le2000$。 对于另外$15\%$的数据,保证给出的树是一条链。 对于另外$15\%$的数据,保证树随机生成。 对于$100\%$的数据,$n\le100000$,$k\le n$。 时间限制:$1s$ 空间限制:$512MB$ 其实有一个结论,对于树上一些点集的一个集合,将他们连成一个联通块,所必须需要选的点的点数可以这样计算:将所有点的dfs序提出来,然后将点集中的点按照dfs序排序,然后dfs序相邻两个点的距离总和设为S(对于排序之后,第一个和最后一个之间也叫做相邻)。然后所需要的点数就是S/2+1了。至于这个为什么成立,可以手动模拟一下按照dfs第一个点开始跑一圈dfs遍历又回到第一个点的整个过程。 于是只要知道这个结论,之后基本上就是套了。每次往集合里加进去一个点,将其dfs序前驱和dfs序后继之间答案删去,然后加上其与前驱和其与后继的答案,从集合里删去一个点也是同理。找前驱后继直接上set吧。 code:
/*
对于一个连续树上子集,其节点必须数为dfs序排序后所有距离+1 
*/
#include<stdio.h>
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<set>
#include<vector>
#include<map>
#include<cmath>
using namespace std;
const int maxn = 200005;
int n,k;

int en[maxn],nt[maxn],owo,la[maxn];
void addedge(int a,int b) {
	en[++owo] = b; nt[owo] = la[a]; la[a] = owo;
}
int dfn[maxn],logg[maxn],dfx,fa[maxn],lac[maxn],ola;
int ST[20][maxn],dep[maxn];
int oldid[maxn];
void dfs(int x,int ba) {
	fa[x] = ba; dfn[x] = ++dfx; ST[0][++ola] = x;
	oldid[dfx] = x;
	dep[x] = dep[ba]+1;
	for(int it=la[x];it;it=nt[it]) {
		if(en[it]==ba) continue;
		dfs(en[it],x);
		ST[0][++ola] = x;
	}
	lac[x] = ola;
}
set<int>se;
int ans = 0,tot;
int getlca(int x,int y) {
	x = lac[x]; y = lac[y]; if(x>y) swap(x,y);
	int k = logg[y-x+1];
	return (dep[ST[k][x]]<dep[ST[k][y-(1<<k)+1]]) ? ST[k][x] : ST[k][y-(1<<k)+1];
}
int getdis(int x,int y) {
	return dep[x] + dep[y] - 2*dep[getlca(x,y)];
}
set<int>::iterator it;
int ANS;
void ins(int x) {
	int dx = dfn[x];
	if(!tot);
	else if(tot==1) {
		ans += getdis(x,oldid[*se.begin()])*2;
	}
	else {
		int hj,qq;
		it = se.lower_bound(dx);
		if(it==se.end()) hj = *se.begin();
		else hj = *it;
		if(it==se.begin()) qq = *se.rbegin();
		else {
		--it; qq = *it;
		}
		ans -= getdis(oldid[qq],oldid[hj]) ;
		ans += getdis(oldid[qq],x); 
		ans += getdis(oldid[hj],x);
	}
	++tot;
	se.insert(dx);
	if(ans/2+1<=k) ANS = max(ANS,tot);
}
void del(int x) {
	int dx = dfn[x];
	se.erase(dx);
	if(tot==1) ;
	else if(tot==2) {
		ans -= getdis(x,oldid[*se.begin()])*2;
	}
	else {
		int hj,qq;
		it = se.lower_bound(dx);
		if(it==se.end()) hj = *se.begin();
		else hj = *it;
		if(it==se.begin()) qq = *se.rbegin();
		else {
		--it; qq = *it;
		}
		ans += getdis(oldid[qq],oldid[hj]) ;
		ans -= getdis(oldid[qq],x); 
		ans -= getdis(oldid[hj],x);
	}
	--tot;
	if(ans/2+1<=k) ANS = max(ANS,tot);
}

int main() {
	ios::sync_with_stdio(false);
	cin>>n>>k;
	logg[0]=logg[1]=0;
	for(int i=2;i<=2*n;i++) logg[i]=logg[i>>1]+1;
	for(int i=1;i<=n-1;i++) {
		int a,b; cin>>a>>b; 
		addedge(a,b); addedge(b,a);
	}
	dfs(1,0);
	int ss = logg[2*n];
	for(int i=1;i<=ss;i++) {
		for(int j=1;j+(1<<i)-1<=ola;j++) {
			ST[i][j] = (dep[ST[i-1][j]]<dep[ST[i-1][j+(1<<(i-1))]]) ? ST[i-1][j] : ST[i-1][j+(1<<(i-1))];
		}
	}
//	cout<<getlca(1,3);
	int R = 0;
	for(int i=1;i<=n;i++) {
		while(R<n&&(ans/2+1<=k)) {
			R++; ins(R);
			if(ans/2+1>k) break;
		}
		del(i);
	}
	cout<<ANS;
}
 
posted @ 2018-09-24 13:47  Newuser233  阅读(8)  评论(0)    收藏  举报