树形dp杂题
树形 杂题
模板/思维题
P1122 最大子树和
求的是树上最大的一个连通分量的大小
那么我们设置
如果
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define mid (l+r>>1)
#define inl inline
#define ls p<<1
#define rs p<<1|1
#define lson ls,l,mid
#define rson rs,mid+1,r
#define pii pair<int,int>
#define eb emplace_back
const int N = 2e5 + 5;
const int inf = 0x3f3f3f3f;
char buf[1<<24] , *p1 , *p2;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<24,stdin),p1==p2)?EOF:*p1++)
// #define getchar() cin.get();
int read()
{
int x = 0 , f = 1;
char ch = getchar();
while ( !isdigit(ch) ) { if ( ch == '-' ) f = -1; ch = getchar(); }
while ( isdigit(ch) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = getchar(); }
return x * f ;
}
int n , m , f[N] , maxx = -inf , a[N];
vector<int> e[N];
inl void add ( int u , int v ) { e[u].eb(v); }
void dfs ( int u , int fa )
{
f[u] = a[u];
for ( auto v : e[u] )
if ( v ^ fa )
{
dfs ( v , u );
if ( f[v] > 0 ) f[u] += f[v];
}
}
signed main ()
{
ios::sync_with_stdio(false);
cin.tie(nullptr) , cout.tie(nullptr);
n = read();
for ( int i = 1 ; i <= n ; i ++ ) a[i] = read();
for ( int i = 1 , u , v ; i < n ; i ++ ) u = read() , v = read() , add ( u , v ) , add ( v , u );
dfs ( 1 , 0 );
for ( int i = 1 ; i <= n ; i ++ ) maxx = max ( maxx , f[i] );
cout << maxx << endl;
return 0;
}
P2016 战略游戏
设置
那么如果这个点不放士兵(
同理 如果这个点放士兵(
#include <bits/stdc++.h>
using namespace std;
#define inl inline
const int N = 1e5 + 10;
const int inf = 0x3f3f3f3f;
inline int read ()
{
int x = 0 , f = 1;
char ch = getchar();
while ( !isdigit ( ch ) ) { if ( ch == '-' ) f = -1; ch = getchar (); }
while ( isdigit ( ch ) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = getchar (); }
return x * f;
}
int n , a[N] , f[N][2];
//设f[u][0]表示当前处理到u节点 然后这个节点不选
//同理 f[u][1]表示当前处理到u节点 这个节点选择
int head[N] , cnt;
struct edge { int to , nxt; } e[N];
void add ( int u , int v ) { e[++cnt] = { v , head[u] }; head[u] = cnt; }
void dfs ( int u , int fa )
{
f[u][1] = 1;
for ( int i = head[u] ; i ; i = e[i].nxt )
{
int v = e[i].to;
if ( v == fa ) continue;
dfs ( v , u );
f[u][0] += f[v][1];
f[u][1] += min ( f[v][1] , f[v][0] );
}
}
signed main ()
{
n = read();
for ( int i = 1 , u , v , k ; i < n ; i ++ )
{
u = read() , k = read();
for ( int i = 1 ; i <= k ; i ++ )
{
v = read();
add ( u , v );
add ( v , u );
}
}
dfs ( 1 , n );
printf ( "%d" , min ( f[1][0] , f[1][1] ) );
return 0;
}
P4084 [USACO17DEC] Barn Painting G
经典套路:设置
那么
#include<bits/stdc++.h>
using namespace std;
#define mid (l+r>>1)
#define inl inline
#define eb emplace_back
#define endl '\n'
#define ls p<<1
#define rs p<<1|1
#define lson ls,l,mid
#define rson rs,mid+1,r
#define pii pair<int,int>
#define fi first
#define se second
#define int long long
#define print(x) cerr<<#x<<'='<<x<<endl
const int N = 1e5 + 5;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f3f3f3f3f;
#define getchar() cin.get()
int read()
{
int x = 0 , f = 1;
char ch = getchar();
while ( !isdigit(ch) ) { if ( ch == '-' ) f = -1; ch = getchar(); }
while ( isdigit(ch) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = getchar(); }
return x * f;
}
int n , k , f[N][4] , a[N];
vector<int> e[N];
inl void add ( int u , int v ) { e[u].eb(v); }
void dfs ( int u , int ff )
{
for ( int i = 1 ; i <= 3 ; i ++ ) f[u][i] = 1;
if ( a[u] )
{
for ( int i = 1 ; i <= 3 ; i ++ )
if ( i ^ a[u] ) f[u][i] = 0;
}
for ( auto v : e[u] )
if ( v ^ ff )
{
dfs ( v , u );
( f[u][1] *= ( f[v][2] + f[v][3] ) ) %= mod;
( f[u][2] *= ( f[v][1] + f[v][3] ) ) %= mod;
( f[u][3] *= ( f[v][1] + f[v][2] ) ) %= mod;
}
}
signed main ()
{
ios::sync_with_stdio(false);
cin.tie(0) , cout.tie(0);
n = read() , k = read();
for ( int i = 1 , u , v ; i < n ; i ++ ) u = read() , v = read() , add ( u , v ) , add ( v , u );
for ( int i = 1 , u , col ; i <= k ; i ++ ) u = read() , col = read() , a[u] = col;
dfs ( 1 , 0 );
cout << ( f[1][1] + f[1][2] + f[1][3] ) % mod << endl;
return 0;
}
P3047 [USACO12FEB] Nearby Cows G
我们记录
那么很显然我们可以一次
同时
#include<bits/stdc++.h>
using namespace std;
#define mid (l+r>>1)
#define inl inline
#define eb
#define endl '\n'
#define ls p<<1
#define rs p<<1|1
#define lson ls,l,mid
#define rson rs,mid+1,r
#define pii pair<int,int>
#define fi first
#define se second
#define print(x) cerr<<#x<<'='<<x<<endl
const int N = 1e5 + 5;
const int K = 25;
#define getchar() cin.get()
int read()
{
int x = 0 , f = 1;
char ch = getchar();
while ( !isdigit(ch) ) { if ( ch == '-' ) f = -1; ch = getchar(); }
while ( isdigit(ch) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = getchar(); }
return x * f;
}
int n , k , f[N][K] , g[N][K] , a[N];
//g[i][j]表示在以i为根的子树中 向下延伸j长度的权值和
//f[i][j]表示在以i为根的子树中 周围j长度的权值和
vector<int> e[N];
inl void add ( int u , int v ) { e[u].eb(v); }
void dfs ( int u , int ff )
{
for ( int i = 0 ; i <= k ; i ++ ) g[u][i] = a[u];
for ( auto v : e[u] )
if ( v ^ ff )
{
dfs ( v , u );
for ( int i = 1 ; i <= k ; i ++ ) g[u][i] += g[v][i-1];
}
}
void dfss ( int u , int ff )
{
for ( auto v : e[u] )
if ( v ^ ff )
{
f[v][1] += f[u][0];
for ( int i = 2 ; i <= k ; i ++ ) f[v][i] += f[u][i-1] - g[v][i-2];
dfss ( v , u );
}
}
signed main ()
{
ios::sync_with_stdio(false);
cin.tie(0) , cout.tie(0);
n = read() , k = read();
for ( int i = 1 , u , v ; i < n ; i ++ ) u = read() , v = read() , add ( u , v ) , add ( v , u );
for ( int i = 1 ; i <= n ; i ++ ) a[i] = read();
dfs ( 1 , 0 );
for ( int i = 1 ; i <= n ; i ++ ) for ( int j = 1 ; j <= k ; j ++ ) f[i][j] = g[i][j];
memcpy ( f , g , sizeof g );
dfss ( 1 , 0 );
for ( int i = 1 ; i <= n ; i ++ ) cout << f[i][k] << endl;
return 0;
}
P2585 [ZJOI2006] 三色二叉树
思路很顺畅 先递归建树再
#include<bits/stdc++.h>
using namespace std;
#define mid (l+r>>1)
#define inl inline
#define eb emplace_back
#define endl '\n'
#define ls p<<1
#define rs p<<1|1
#define lson ls,l,mid
#define rson rs,mid+1,r
#define pii pair<int,int>
#define fi first
#define se second
#define print(x) cerr<<#x<<'='<<x<<endl
const int N = 5e5 + 5;
const int K = 25;
#define getchar() cin.get()
int read()
{
int x = 0 , f = 1;
char ch = getchar();
while ( !isdigit(ch) ) { if ( ch == '-' ) f = -1; ch = getchar(); }
while ( isdigit(ch) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = getchar(); }
return x * f;
}
int n , tot , rt , ch[N][2] , f[N][3] , g[N][3];
string s;
void build ( int &u )
{
u = ++tot;
if ( s[u-1] == '1' ) build ( ch[u][0] );
else if ( s[u-1] == '2' ) build ( ch[u][0] ) , build ( ch[u][1] );
}
void dfs ( int u )
{
int l = ch[u][0] , r = ch[u][1];
if ( l ) dfs(l);
if ( r ) dfs(r);
if ( !l && !r ) f[u][0] = g[u][0] = 1;
f[u][0] = max ( f[l][1] + f[r][2] , f[l][2] + f[r][1] ) + 1;
f[u][1] = max ( f[l][0] + f[r][2] , f[l][2] + f[r][0] );
f[u][2] = max ( f[l][0] + f[r][1] , f[l][1] + f[r][0] );
g[u][0] = min ( g[l][1] + g[r][2] , g[l][2] + g[r][1] ) + 1;
g[u][1] = min ( g[l][0] + g[r][2] , g[l][2] + g[r][0] );
g[u][2] = min ( g[l][0] + g[r][1] , g[l][1] + g[r][0] );
}
signed main ()
{
ios::sync_with_stdio(false);
cin.tie(0) , cout.tie(0);
cin >> s;
build(rt);
dfs ( rt );
cout << max ( max ( f[rt][0] , f[rt][1] ) , f[rt][2] ) << ' ' << min ( min ( g[rt][0] , g[rt][1] ) , g[rt][2] ) << endl;
return 0;
}
[P1131 [ZJOI2007] 时态同步
我们可以维护最长链 固定最长链上的价值不动 然后提升其余链的价值 这样一定不劣
树形
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define mid (l+r>>1)
#define inl inline
#define eb emplace_back
#define pii pair<int,int>
#define fi first
#define se second
#define int long long
const int N = 1e6 + 5;
//char buf[1<<24] , *p1 , *p2;
//#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<24,stdin),p1==p2)?EOF:*p1++)
#define getchar() cin.get();
int read()
{
int x = 0 , f = 1;
char ch = getchar();
while ( !isdigit(ch) ) { if ( ch == '-' ) f = -1; ch = getchar(); }
while ( isdigit(ch) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = getchar(); }
return x * f ;
}
int n , s , ans , dis[N];
vector<pii> e[N];
inl void add ( int u , int v , int w ) { e[u].eb(v,w); }
void dfs ( int u , int fa )
{
for ( auto p : e[u] )
{
int v = p.fi , w = p.se;
if ( v ^ fa )
{
dfs ( v , u );
dis[u] = max ( dis[u] , dis[v] + w );
}
}
for ( auto p : e[u] )
{
int v = p.fi , w = p.se;
if ( v ^ fa ) ans += dis[u] - ( dis[v] + w );
}
}
signed main ()
{
ios::sync_with_stdio(false);
cin.tie(nullptr) , cout.tie(nullptr);
n = read() , s = read();
for ( int i = 1 , u , v , w ; i < n ; i ++ ) u = read() , v = read() , w = read() , add ( u , v , w ) , add ( v , u , w );
dfs ( s , 0 );
cout << ans << endl;
return 0;
}
P4438 [HNOI/AHOI2018] 道路
解释:乡村为叶节点 城市为中间节点 整颗树是二叉树
设置
相当于是要么这个点要么翻修铁路 要么翻修公路 更新对应的权值
对于叶子节点 我们预处理出所有的
发现
#include<bits/stdc++.h>
using namespace std;
#define mid (l+r>>1)
#define inl inline
#define eb emplace_back
#define endl '\n'
#define ls p<<1
#define rs p<<1|1
#define lson ls,l,mid
#define rson rs,mid+1,r
#define pii pair<int,int>
#define fi first
#define se second
#define print(x) cerr<<#x<<'='<<x<<endl
#define int long long
const int N = 4e5 + 5;
#define getchar() cin.get()
int read()
{
int x = 0 , f = 1;
char ch = getchar();
while ( !isdigit(ch) ) { if ( ch == '-' ) f = -1; ch = getchar(); }
while ( isdigit(ch) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = getchar(); }
return x * f;
}
int n , dfn[N] , f[405][45][45] , a[N] , b[N] , c[N] , son[N][2];
void dfs ( int u , int timer , int limi , int limj )
{
dfn[u] = timer;
if ( u >= n )
{
for ( int i = 0 ; i <= limi ; i ++ )
for ( int j = 0 ; j <= limj ; j ++ )
f[dfn[u]][i][j] = c[u] * ( a[u] + i ) * ( b[u] + j );
return;
}
dfs ( son[u][0] , timer + 1 , limi + 1 , limj ) , dfs ( son[u][1] , timer + 2 , limi , limj + 1 );
for ( int i = 0 ; i <= limi ; i ++ )
for ( int j = 0 ; j <= limj ; j ++ )
f[dfn[u]][i][j] = min ( f[dfn[son[u][0]]][i+1][j] + f[dfn[son[u][1]]][i][j] , f[dfn[son[u][0]]][i][j] + f[dfn[son[u][1]]][i][j+1] );
}
signed main ()
{
ios::sync_with_stdio(false);
cin.tie(0) , cout.tie(0);
n = read();
for ( int i = 1 ; i < n ; i ++ )
{
int s = read() , t = read();
s = ( s < 0 ) ? ( -s + n - 1 ) : s;
t = ( t < 0 ) ? ( -t + n - 1 ) : t;
son[i][0] = s , son[i][1] = t;
}
for ( int i = 1 ; i <= n ; i ++ ) a[i+n-1] = read() , b[i+n-1] = read() , c[i+n-1] = read();
dfs ( 1 , 1 , 0 , 0 );
cout << f[1][0][0] << endl;
return 0;
}
Garland
我们需要达到的目的是将一整棵树分成点权相同的三个部分
那么首先如果
否则我们进行树上的贪心
那么如果
#include<bits/stdc++.h>
using namespace std;
#define mid (l+r>>1)
#define inl inline
#define eb emplace_back
#define endl '\n'
#define ls p<<1
#define rs p<<1|1
#define lson ls,l,mid
#define rson rs,mid+1,r
#define pii pair<int,int>
#define fi first
#define se second
#define mkp make_pair
#define print(x) cerr<<#x<<'='<<x<<endl
const int N = 1e6 + 5;
#define getchar() cin.get()
int read()
{
int x = 0 , f = 1;
char ch = getchar();
while ( !isdigit(ch) ) { if ( ch == '-' ) f = -1; ch = getchar(); }
while ( isdigit(ch) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = getchar(); }
return x * f;
}
int a[N] , sum , n , f[N] , rt;
vector<int> e[N] , vec;
inl void add ( int u , int v ) { e[u].eb(v); }
void dfs ( int u , int ff )
{
f[u] = a[u];
for ( auto v : e[u] )
if ( v ^ ff )
{
dfs ( v , u );
f[u] += f[v];
}
if ( f[u] == sum ) vec.eb(u) , f[u] = 0;
}
signed main ()
{
ios::sync_with_stdio(false);
cin.tie(0) , cout.tie(0);
n = read();
for ( int i = 1 , ff ; i <= n ; i ++ )
{
ff = read();
if ( ff ) add ( ff , i ) , add ( i , ff );
else rt = i;
sum += ( a[i] = read() );
}
if ( sum % 3 ) return cout << -1 << endl , 0;
sum /= 3;
dfs ( rt , 0 );
if ( vec.size() <= 2 ) { cout << -1 << endl; exit(0); }
else cout << vec[0] << ' ' << vec[1] << endl;
return 0;
}
树上背包
P2014 [CTSC1997] 选课
设置
根据套路 我们在
注意倒序枚举
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define inl inline
const int N = 1e3 + 5;
const int inf = 0x3f3f3f3f;
int read ()
{
int x = 0 , f = 1;
char ch = cin.get();
while ( !isdigit ( ch ) ) { if ( ch == '-' ) f = -1; ch = cin.get(); }
while ( isdigit ( ch ) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = cin.get(); }
return x * f;
}
int n , f[N][N] , m;
int head[N] , cnt;
struct node { int to , nxt; } e[N];
inl void add ( int u , int v ) { e[++cnt] = { v , head[u] }; head[u] = cnt; }
void dfs ( int u )
{
for ( int i = head[u] ; i ; i = e[i].nxt )
{
int v = e[i].to;
dfs(v);
for ( int j = m ; j ; j -- )
for ( int k = 1 ; k < j ; k ++ )//不能枚举到j 因为我们状态定义的就是u这个根节点必须选 因为只有选了这个节点才能选子节点
f[u][j] = max ( f[u][j] , f[v][j-k] + f[u][k] );
}
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0) , cout.tie(0);
n = read() , m = read();
for ( int i = 1 ; i <= n ; i ++ )
{
int u = read();
f[i][1] = read();
add ( u , i );
}
m ++ , dfs(0);
cout << f[0][m] << endl;
return 0;
}
P2015 二叉苹果树
和上一道题的转移状态只有一点不同:
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define mid (l+r>>1)
#define inl inline
#define ls p<<1
#define rs p<<1|1
#define lson ls,l,mid
#define rson rs,mid+1,r
#define pii pair<int,int>
#define eb emplace_back
const int N = 100 + 5;
char buf[1<<24] , *p1 , *p2;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<24,stdin),p1==p2)?EOF:*p1++)
// #define getchar() cin.get();
int read()
{
int x = 0 , f = 1;
char ch = getchar();
while ( !isdigit(ch) ) { if ( ch == '-' ) f = -1; ch = getchar(); }
while ( isdigit(ch) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = getchar(); }
return x * f ;
}
int n , m , f[N][N];
vector<pii> e[N];
inl void add ( int u , int v , int w ) { e[u].eb(v,w); }
void dfs ( int u , int fa )
{
for ( auto [v,w] : e[u] )
if ( v ^ fa )
{
dfs ( v , u );
for ( int j = m ; j ; j -- )
for ( int k = 1 ; k <= j ; k ++ )
f[u][j] = max ( f[u][j] , f[v][k-1] + f[u][j-k] + w );
}
}
signed main ()
{
ios::sync_with_stdio(false);
cin.tie(nullptr) , cout.tie(nullptr);
n = read() , m = read();
for ( int i = 1 ; i < n ; i ++ )
{
int u = read() , v = read() , w = read();
add ( u , v , w ) , add ( v , u , w );
}
dfs ( 1 , 0 );
cout << f[1][m] << endl;
return 0;
}
P1273 有线电视网
设置
注意 最后统计答案的时候从大到小枚举用户个数
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define mid (l+r>>1)
#define inl inline
#define ls p<<1
#define rs p<<1|1
#define lson ls,l,mid
#define rson rs,mid+1,r
#define pii pair<int,int>
#define eb emplace_back
const int N = 3000 + 5;
const int inf = 0x3f3f3f3f;
char buf[1<<24] , *p1 , *p2;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<24,stdin),p1==p2)?EOF:*p1++)
// #define getchar() cin.get();
int read()
{
int x = 0 , f = 1;
char ch = getchar();
while ( !isdigit(ch) ) { if ( ch == '-' ) f = -1; ch = getchar(); }
while ( isdigit(ch) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = getchar(); }
return x * f ;
}
int n , m , f[N][N] , a[N] , sz[N];
vector<pii> e[N];
inl void add ( int u , int v , int w ) { e[u].eb(v,w); }
void dfs ( int u , int fa )
{
if ( u >= n - m + 1 ) return f[u][1] = a[u] , sz[u] = 1 , void();
for ( auto [v,w] : e[u] )
if ( v ^ fa )
{
dfs ( v , u );
sz[u] += sz[v];
for ( int j = sz[u] ; j ; j -- )
for ( int k = 1 ; k <= min ( j , sz[v] ) ; k ++ )
f[u][j] = max ( f[u][j] , f[v][k] + f[u][j-k] - w );
}
}
signed main ()
{
ios::sync_with_stdio(false);
cin.tie(nullptr) , cout.tie(nullptr);
n = read() , m = read();
for ( int i = 1 ; i <= n - m ; i ++ )
{
int k = read();
for ( int j = 1 ; j <= k ; j ++ )
{
int A = read() , C = read();
add ( i , A , C ) , add ( A , i , C );
}
}
for ( int i = n - m + 1 ; i <= n ; i ++ ) a[i] = read();
memset ( f , -inf , sizeof f );
for ( int i = 1 ; i <= n ; i ++ ) f[i][0] = 0;
dfs ( 1 , 0 );
for ( int i = m ; i >= 0 ; i -- ) if ( f[1][i] >= 0 ) return cout << i << endl , 0;
return 0;
}
P1270 “访问”美术馆
设置
显然有转移方程
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define mid (l+r>>1)
#define inl inline
#define ls p<<1
#define rs p<<1|1
#define lson ls,l,mid
#define rson rs,mid+1,r
#define pii pair<int,int>
#define eb emplace_back
const int N = 6000 + 5;
const int inf = 0x3f3f3f3f;
char buf[1<<24] , *p1 , *p2;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<24,stdin),p1==p2)?EOF:*p1++)
// #define getchar() cin.get();
int read()
{
int x = 0 , f = 1;
char ch = getchar();
while ( !isdigit(ch) ) { if ( ch == '-' ) f = -1; ch = getchar(); }
while ( isdigit(ch) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = getchar(); }
return x * f ;
}
int n , m , f[N][N] , a[N] , tot = 1 , tim;
vector<pii> e[N];
inl void add ( int u , int v , int w ) { e[u].eb(v,w); }
void build ( int u , int fa )
{
int w = read() , v = read();
add ( fa , u , w << 1 ) , add ( u , fa , w << 1 );//进去+出来
if ( v ) return a[u] = v , void();
build ( ++tot , u ) , build ( ++tot , u );
}
void dfs ( int u , int fa )
{
if ( a[u] ) { for ( int i = 1 ; i <= a[u] ; i ++ ) f[u][i*5] = i; return; }
for ( auto [v,w] : e[u] )
if ( v ^ fa )
{
dfs ( v , u );
for ( int j = tim ; j ; j -- )
for ( int k = w ; k <= j ; k ++ )
f[u][j] = max ( f[u][j] , f[u][j-k] + f[v][k-w] );
}
}
signed main ()
{
ios::sync_with_stdio(false);
cin.tie(nullptr) , cout.tie(nullptr);
tim = read();
build ( ++tot , 1 );
dfs(1,0);
cout << f[1][tim-1] << endl;
return 0;
}
P3360 偷天换日
和上道题一样 只是叶节点处理的时候换成了
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define mid (l+r>>1)
#define inl inline
#define ls p<<1
#define rs p<<1|1
#define lson ls,l,mid
#define rson rs,mid+1,r
#define pii pair<int,int>
#define eb emplace_back
const int N = 600 + 5;
char buf[1<<24] , *p1 , *p2;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<24,stdin),p1==p2)?EOF:*p1++)
// #define getchar() cin.get();
int read()
{
int x = 0 , f = 1;
char ch = getchar();
while ( !isdigit(ch) ) { if ( ch == '-' ) f = -1; ch = getchar(); }
while ( isdigit(ch) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = getchar(); }
return x * f ;
}
int n , m , f[N][N] , tot = 1 , tim , k[N];
vector<pii> e[N];
inl void add ( int u , int v , int w ) { e[u].eb(v,w); }
struct node { int wei , val; } a[N][N];
void build ( int u , int fa )
{
int w = read(); k[u] = read();
add ( fa , u , 2 * w ) , add ( u , fa , 2 * w );
if ( k[u] )
{
for ( int i = 1 ; i <= k[u] ; i ++ ) a[u][i].val = read() , a[u][i].wei = read();
return;
}
build ( ++ tot , u );
build ( ++ tot , u );
}
void dfs ( int u , int fa )
{
if ( k[u] )
{
for ( int i = 1 ; i <= k[u] ; i ++ )
for ( int j = tim ; j >= a[u][i].wei ; j -- )
f[u][j] = max ( f[u][j] , f[u][j-a[u][i].wei] + a[u][i].val );
return;
}
for ( auto [v,w] : e[u] )
if ( v ^ fa )
{
dfs ( v , u );
for ( int j = tim ; j ; j -- )
for ( int k = w ; k <= j ; k ++ )
f[u][j] = max ( f[u][j] , f[v][k-w] + f[u][j-k] );
}
}
signed main ()
{
ios::sync_with_stdio(false);
cin.tie(nullptr) , cout.tie(nullptr);
tim = read();
build ( ++ tot , 1 );
dfs ( 1 , 0 );
cout << f[1][tim-1] << endl;
return 0;
}
换根
P3478 [POI2008] STA-Station
换根
我们考虑先将以
一个很朴素的想法就是换
发现我们如果知道了树上父亲节点的答案 就可以推出子节点的答案
例如:
这里以

换成以

可以发现
抽象到代码中:上面的
所以我们第一遍先从下到上求出深度 第二遍从上到下推即可
记得
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define mid (l+r>>1)
#define inl inline
#define eb emplace_back
#define pii pair<int,double>
#define fi first
#define se second
#define mkp make_pair
#define fi first
#define se second
#define int long long
const int N = 1e6 + 5;
const double inf = 0x3f3f3f3f;
// char buf[1<<24] , *p1 , *p2;
// #define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<24,stdin),p1==p2)?EOF:*p1++)
#define getchar() cin.get();
int read()
{
int x = 0 , f = 1;
char ch = getchar();
while ( !isdigit(ch) ) { if ( ch == '-' ) f = -1; ch = getchar(); }
while ( isdigit(ch) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = getchar(); }
return x * f ;
}
int n , m , ans , id , f[N] , dep[N] , sz[N];
vector<int> e[N];
inl void add ( int u , int v ) { e[u].eb(v); }
void dfs ( int u , int fa )
{
dep[u] = dep[fa] + 1 , sz[u] = 1;
for ( auto v : e[u] )
if ( v ^ fa )
{
dfs ( v , u );
sz[u] += sz[v];
}
}
void DFS ( int u , int fa )
{
for ( auto v : e[u] )
if ( v ^ fa )
{
f[v] = f[u] - sz[v] + n - sz[v];
DFS ( v , u );
}
}
signed main ()
{
ios::sync_with_stdio(false);
cin.tie(nullptr) , cout.tie(nullptr);
n = read();
for ( int i = 1 , u , v ; i < n ; i ++ ) u = read() , v = read() , add ( u , v ) , add ( v , u );
dfs ( 1 , 0 );
for ( int i = 1 ; i <= n ; i ++ ) f[1] += dep[i];
DFS ( 1 , 0 );
for ( int i = 1 ; i <= n ; i ++ ) if ( ans < f[i] ) ans = f[i] , id = i;
cout << id << endl;
return 0;
}
Choosing Capital for Treeland
可以先将根节点需要的翻转次数先算出来 那么对于
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define mid (l+r>>1)
#define inl inline
#define eb emplace_back
#define ls p<<1
#define rs p<<1|1
#define lson ls,l,mid
#define rson rs,mid+1,r
#define pii pair<int,int>
#define fi first
#define se second
const int N = 2e5 + 5;
const int inf = 0x3f3f3f3f;
//char buf[1<<24] , *p1 , *p2;
//#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<24,stdin),p1==p2)?EOF:*p1++)
#define getchar() cin.get();
int read()
{
int x = 0 , f = 1;
char ch = getchar();
while ( !isdigit(ch) ) { if ( ch == '-' ) f = -1; ch = getchar(); }
while ( isdigit(ch) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = getchar(); }
return x * f ;
}
int n , minn = inf , f[N];
vector<pii> e[N];
inl void add ( int u , int v , int w ) { e[u].eb(v,w); }
void dfs ( int u , int ff )
{
for ( auto p : e[u] )
{
int v = p.fi , w = p.se;
if ( v ^ ff )
{
dfs ( v , u );
f[u] += f[v] + w;
}
}
}
void dfss ( int u , int ff )
{
for ( auto p : e[u] )
{
int v = p.fi , w = p.se;
if ( v ^ ff )
{
f[v] = f[u] + ( w ? -1 : 1 );
dfss ( v , u );
}
}
}
signed main ()
{
ios::sync_with_stdio(false);
cin.tie(nullptr) , cout.tie(nullptr);
n = read();
for ( int i = 1 , u , v ; i < n ; i ++ ) u = read() , v = read() , add ( u , v , 0 ) , add ( v , u , 1 );
dfs ( 1 , 0 );
dfss ( 1 , 0 );
for ( int i = 1 ; i <= n ; i ++ ) minn = min ( minn , f[i] );
cout << minn << endl;
for ( int i = 1 ; i <= n ; i ++ ) if ( f[i] == minn ) cout << i << ' ';
return 0;
}
P2986 [USACO10MAR] Great Cow Gathering G
一定注意 第二次
#include<bits/stdc++.h>
using namespace std;
#define mid (l+r>>1)
#define inl inline
#define eb emplace_back
#define endl '\n'
#define ls p<<1
#define rs p<<1|1
#define lson ls,l,mid
#define rson rs,mid+1,r
#define pii pair<int,int>
#define fi first
#define se second
#define int long long
#define print(x) cerr<<#x<<'='<<x<<endl
const int N = 1e5 + 5;
const int inf = 0x3f3f3f3f3f3f3f3f;
#define getchar() cin.get()
int read()
{
int x = 0 , f = 1;
char ch = getchar();
while ( !isdigit(ch) ) { if ( ch == '-' ) f = -1; ch = getchar(); }
while ( isdigit(ch) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = getchar(); }
return x * f;
}
int n , m , r , mod , a[N] , sz[N] , szz[N] , f[N] , dep[N] , minn = inf;
vector<pii> e[N];
inl void add ( int u , int v , int w ) { e[u].eb(v,w); }
void dfs ( int u , int ff )
{
sz[u] = a[u];
for ( auto p : e[u] )
{
int v = p.fi , w = p.se;
if ( v ^ ff ) dep[v] = dep[u] + w , dfs ( v , u ) , sz[u] += sz[v];
}
}
void dfss ( int u , int ff )
{
for ( auto p : e[u] )
{
int v = p.fi , w = p.se;
if ( v ^ ff ) f[v] = f[u] + ( sz[1] - sz[v] * 2 ) * w , dfss ( v , u );
}
}
signed main ()
{
ios::sync_with_stdio(false);
cin.tie(0) , cout.tie(0);
n = read();
for ( int i = 1 ; i <= n ; i ++ ) a[i] = read();
for ( int i = 1 , u , v , w ; i < n ; i ++ ) u = read() , v = read() , w = read() , add ( u , v , w ) , add ( v , u , w );
dfs ( 1 , 0 );
for ( int i = 1 ; i <= n ; i ++ ) f[1] += a[i] * dep[i];
dfss ( 1 , 0 );
for ( int i = 1 ; i <= n ; i ++ ) minn = min ( minn , f[i] );
cout << minn << endl;
return 0;
}
Tree Painting
同上()
#include <bits/stdc++.h>
using namespace std;
#define inl inline
#define eb emplace_back
#define endl '\n'
#define int long long
const int N = 2e5 + 5;
inl int read ()
{
int x = 0 , f = 1;
char ch = getchar();
while ( !isdigit ( ch ) ) { if ( ch == '-' ) f = -1; ch = getchar (); }
while ( isdigit ( ch ) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = getchar (); }
return x * f;
}
int f[N] , g[N] , maxx , sz[N] , n;
vector<int> e[N];
inl void add ( int u , int v ) { e[u].eb(v); }
void dfs ( int u , int ff )
{
sz[u] = 1;
for ( auto v : e[u] )
if ( v ^ ff )
dfs ( v , u ) , f[u] += f[v] , sz[u] += sz[v];
f[u] += sz[u];
}
void dfss ( int u , int ff )
{
for ( auto v : e[u] )
if ( v ^ ff )
{
g[v] = g[u] - sz[v] + n - sz[v];
dfss ( v , u );
}
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0) , cout.tie(0);
n = read();
for ( int i = 1 , u , v ; i < n ; i ++ ) u = read() , v = read() , add ( u , v ) , add ( v , u );
dfs ( 1 , 0 ) , g[1] = f[1];
dfss ( 1 , 0 );
for ( int i = 1 ; i <= n ; i ++ ) maxx = max ( g[i] , maxx );
cout << maxx << endl;
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】