题解
答案显然递减,并且变化点只有根号个。当路径长度>=sqrt(n)时,答案显然小于根号n
所以二分答案找变化点即可
这样根号的性质很常见!
还有一类思路是sz不同的子树只有根号种
这题还有启发式合并的做法
用线段树维护1-sz[x]的答案和最长还剩的路径,每次启发式合并(x,y),分1-sz[y],sz[y] + 1-sz[x],sz[x] + 1,sz[x] + sz[y]三段。
细节超级多,非常难写。这样的题一定要找到最简便的方法。
写这种方法的确浪费时间!费力不讨好!
积累思路:
树上的dp用线段树维护O(子树)大小的信息,合并的时候考虑能否线段树合并或者启发式合并
代码是WA的,合并的时候如果当前根参与构成答案有问题。有时间再调把
#include<bits/stdc++.h>
using namespace std;
#define rep(i,l,r) for(register int i = l ; i <= r ; i++)
#define repd(i,r,l) for(register int i = r ; i >= l ; i--)
#define rvc(i,S) for(register int i = 0 ; i < (int)S.size() ; i++)
#define rvcd(i,S) for(register int i = ((int)S.size()) - 1 ; i >= 0 ; i--)
#define fore(i,x)for (register int i = head[x] ; i ; i = e[i].next)
#define forup(i,l,r) for (register int i = l ; i <= r ; i += lowbit(i))
#define fordown(i,id) for (register int i = id ; i ; i -= lowbit(i))
#define pb push_back
#define prev prev_
#define stack stack_
#define mp make_pair
#define fi first
#define se second
#define lowbit(x) (x&(-x))
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef pair<ll,ll> pr;
const ll inf = 2e18;
const int N = 3e6 + 10;
const int maxn = 100020;
const ll mod = 1e9 + 7;
int rt[maxn];
int sz[maxn],n,mxl[maxn];
vector <int> e[maxn];
namespace Seg{
#define ls(x) ls[x]
#define rs(x) rs[x]
const int M = 4e6 + 20;
int mx[M],ls[M],rs[M],mn[M],s[M],add[M],tot;
inline void update(int x){
mn[x] = min(mn[ls(x)],mn[rs(x)]);
}
inline void Addmx(int x,int d){
mx[x] += d;
mn[x] -= d;
add[x] += d;
}
inline void Max(int x,int d,int d2){
mx[x] = max(mx[x],d);
mn[x] = min(mn[x],d2);
}
inline void pushdown(int x,int l,int mid){
if ( add[x] ){
if ( !ls[x] ) ls[x] = ++tot,mn[tot] = l;
if ( !rs[x] ) rs[x] = ++tot,mn[tot] = mid + 1; //动态建树pushdown的时候要考虑左右儿子不存在的情况!
Addmx(ls[x],add[x]);
Addmx(rs[x],add[x]);
add[x] = 0;
}
if ( mx[x] ){
if ( !ls[x] ) ls[x] = ++tot,mn[tot] = l;
if ( !rs[x] ) rs[x] = ++tot,mn[tot] = mid + 1; //动态建树pushdown的时候要考虑左右儿子不存在的情况!
Max(ls[x],mx[x],l - mx[x]);
Max(rs[x],mx[x],mid + 1 - mx[x]);
mx[x] = 0;
}
}
void modify_ans(int &x,int l,int r,int L,int R,int d){
//合并上一条长度为d的链,注意不能成为答案时长度只能去max
if ( L > R ) return;
if ( !x ) x = ++tot , mn[x] = l;
if ( l == r ){
if ( d + mx[x] >= l ) s[x]++ , mx[x] = 0 , mn[x] = l;
else Max</