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