【题解】codeforces 1039D. You Are Given a Tree 树形dp+二分答案

题解

答案显然递减,并且变化点只有根号个。当路径长度>=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</
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值