機房練習賽4 7 分士多啤梨 樹上DP

2021-07-30 05:32:32 字數 3195 閱讀 8834

院子裡有一顆又高又大的士多啤梨樹,士多啤梨樹有n個節點,每個節點都結了乙個士多啤梨,吃掉第i個結點的士多啤梨可以得到ai的營養值,由於士多啤梨可能會壞掉,所以ai可能為負值,也可能為0。

現在要砍掉這顆樹的兩條邊,使樹變成三份,並且使得三份各自士多啤梨營養值的和恰好一樣。請問是否有這樣的方法呢?如果有,請輸出yes,否則輸出no。

【輸入格式】

第一行乙個數t,表示測試點的個數。

接下來t組:

每組第一行乙個數n,表示結點的個數。

接下來n行,每行兩個數fai和ai,表示第i個結點的父親是fai,第i個結點有營養值為ai的士多啤梨,根節點的fai記為0.

【輸出格式】

輸出t行,如果第t組有解,則輸出yes,否則輸出no

【輸入樣例】

2 6

2 4

0 5

4 2

2 1

1 1

4 2

6 2 4

0 6

4 2

2 1

1 1

4 4 2

【輸出樣例】

yes

no【樣例解釋】

第一組可以切掉1號和4號的父邊,形成均等的三份。

【資料規模】

10% 資料滿足3≤n≤100。

100% 資料滿足t≤20,3≤n≤100000。-100≤ai≤100

【解法】

樹形dp。

首先如果所有值的和不是3的倍數就是no,並且每乙份的值必須要是所有士多啤梨值和的1/3,記k為這個值。

所以統計乙個子樹的權值和,以及乙個dp[i],表示i為根的子樹中是否存在乙個權值為k的子樹。

有解的情況分為以下兩種:

1. 如果當前結點i的兒子中,有兩個兒子s1,s2,dp[s1]和dp[s2]都被標記為true。此時切掉s1和s2的父邊為乙個可行方案。

2. 如果當前結點不是根,子樹和恰好為2*k,並且其子樹中存在權值為k的子樹。此時切掉其父邊,以及它某個後代的父邊,形成乙個可行的方案。

只要判斷是否存在這兩種情況即可。

/*由於資料太水,我這個大暴力過了,其實我這個方法與上面略有不同,他先在樹上跑一次dfs,算出所有點及其子節點的營養值。列舉所有這樣的點,分別求lca(我不知道這樣還能過)*/

#include

#include

using namespace std;

const int n = 500010;

const int m = n + n;

const int p = 16;

inline int

read()

while(ch>='0' && ch <='9')

return

x*f;

}int n, t;

int head[n], dest[m], last[m], dast[m], etot;

int dep[n], anc[n][p+1], sum[n], in[n];

void adde( int u, int v )

void dfs( int u, int f )

}int lca( int u, int v )

int main() int ddf;

dfs(0,0);

int yu = sum[0]/3;

intq[10000],tail=0;

for( register int i = 1; i <= n; i++ )

}int fg,jk = 0;

for( register int i = 2; i <= tail; i++ )

for( int j = 1; j < i; j++ )

if( i != j && jk == 0 )

}if( jk ) else

}return

0;}

std

#include

#include

#include

#include

#include

#include

#include

#include

#define rep(i, a, b) for(int i = a; i <= b; i++)

#define repd(i, a, b) for(int i = b; i >= a; i--)

#define sz(x) (int)((x).size())

#define ms(x, y) memset(x, y, sizeof(x))

#define pb push_back

#define ll long long

#define mp make_pair

using

namespace

std;

const

int n = 100005;

int fa[n];

int dis[n];

int n;

int t[n];

int s[n];

int dp[n];

struct edge e[n];

int b[n];

int en;

void addedge(int u, int v)

vector

xu;

queue

q;void bfs(int rt)

}}bool check()

if(sum % 3 != 0)

sum /= 3;

bfs(rt);

repd(i, 1, n)

ms(dp, 0);

repd(i, 1, n)

else

u = dp[e[j].v];}}

if(u != 0) dp[now] = u;

if(t[now] == sum) dp[now] = now;

}//rep(i,1,n)printf("%d ", dp[i]);

return

false;

}int main()

return

0;}

20170117 機房 練習賽

現代科學,面廣枝繁,不是一輩子學得了的。惟一的辦法是集中精力,先打破一缺口,建立一塊或幾塊根據地,然後乘勝追擊,逐步擴大研究領域。此法單刀直入,易見成效。王梓坤 我熱愛生活,我是一名快速成長的oier include include include define program name color...

機房練習賽 Dinner

本來看到這道題的第一想法是環形區間dp的,但是模擬完樣例我就恍然大悟,在10的時間內可以同時讓1,5點完餐,那不就是找最大值得最小值嗎?然後就是二分答案了,二分最少時間。然後就是我的玄學check 我在考試的時候是想到了變成二倍鏈在區間上處理的,但我直接o n 處理了每個區間的和不大於x的塊,然後列...

機房練習賽4 3 drive

input file drive.in output file drive.out time limit 2 second 工頭cky 最近開了一家 公司,開始經商。作為cky 的忠實小弟,jyb 當了cky 老總的司機。一天晚上,cky 突然找到了乙個新的客戶,所以第二天一早要急著從成都去上海談生...