【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;
}

浙公网安备 33010602011771号