院子裡有一顆又高又大的士多啤梨樹,士多啤梨樹有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 突然找到了乙個新的客戶,所以第二天一早要急著從成都去上海談生...