$\frac{1}{4}$遇到了一道水題,雙徹底不會作,因而去請教小$D$。小$D$看了${0.607}^2$眼就切掉了這題,嘲諷了$\frac{1}{4}$一番就離開了。因而,$\frac{1}{4}$只好來問你,這道題是這樣的:html
有一棵$n$個節點的樹,每條邊長度爲$1$,顏色爲黑或白。
能夠執行若干次以下操做:選擇一條簡單路徑,反轉路徑上全部邊的顏色。
對於某些邊,要求在操做結束時爲某一種顏色。
給定每條邊的初始顏色,求最小操做數,以及知足操做數最小時,最小的操做路徑長度和。c++
從文件$w.in$中讀入數據。
第一行,一個正整數$n$。
接下來$n−1$行,每行四個整數$a,b,c,d$:
$\bullet$樹中有一條邊鏈接$a$和$b$。
$\bullet c=0,1$表示初始顏色爲白色、黑色。
$\bullet d=0,1,2$表示最終要求爲白色、要求爲黑色、沒有要求。spa
輸出到文件$w.out$中。
輸出一行,兩個整數,表示最小操做數、操做數最小時的最小路徑長度和。htm
樣例輸入1:blog
5
2 1 1 0
1 3 0 1
2 4 1 2
5 2 1 1get
樣例輸出1:it
1 2io
樣例輸入2:class
3
1 3 1 2
2 1 0 0im
樣例輸出2:
0 0
樣例輸入3:
6
1 3 0 1
1 2 0 2
2 4 1 0
4 5 1 0
5 6 0 2
樣例輸出3:
1 4
樣例$1$解釋:
操做路徑$\{2,1,3\}$。
數據範圍:
保證給出的圖爲一棵樹,有$n\in [1,10^5],a,b\in [1,n],c\in \{0,1\},d\in\{0,1,2\}$。
看到了這道題,我就像到了前一陣作過的一道題:虎。
而後我就死了……
那道題能夠用貪心解決,可是這道題咱們還須要回答最小的操做路徑長度和……
不過有一些貪心策略仍是能夠利用一下的:
$\alpha.$每一條邊不可能被翻轉兩次以上。
$\beta.$對於一個邊集$E$,咱們所須要翻轉的次數爲這個邊集中奇數點的個數除$2$。
這道題要求咱們在保證第一問最小的狀況下儘量保證第二問最小,因此這很難搞(竟然連部分分都沒有,傷心……)。
如今咱們來考慮如何求出第二問,首先,定義$dp[i][0/1]$表示鏈接$i$的邊是否翻轉的最小代價(爲方便,如下用二元組$pair<int,int>$分別表示第一問和第二問)。
如今考慮如何將兒子轉移給父親,設$w_1$表示已經轉移的兒子中有一條與當前節點的連邊翻轉了的最小代價,$w_2$則表示尚未這樣的一條邊,則:
$$w_1=\min(w_1+dp[v][0],w_2+dp[v][1])$$
$$w_2=\min(w_1+dp[v][1],w_2+dp[v][0])$$
初始值:$w_1=(inf,inf),w_2=(0,0)$。
那麼,如今咱們已經求出了$w_1$和$w_2$,在來考慮如何更新$dp$中的答案。
這時候分兩種狀況:
$\alpha.$頭頂的邊必定要翻轉:
$$dp[i][0]=(inf,inf)$$
$$dp[i][1]=\min((w1.first,w1.second+1),(w2.first+1,w2.second+1))$$
$\beta.$頭頂的邊不須要要翻轉:
$$dp[i][0]=\min((w1.first+1,w1.second),w2)$$
$$dp[i][1]=(inf,inf)$$
最後的答案就是,第一問:$\dfrac{dp[i][0].first}{2}$;第二問:$dp[i][0].second$。
時間複雜度:$\Theta(n)$。
指望得分:$100$分。
實際得分:$100$分。
#include<bits/stdc++.h>
using namespace std;
const int inf=0x3f3f3f3f;
struct rec{int nxt,to,w;}e[200001];
int n;
int head[100001],cnt;
pair<int,int> dp[2][100001];
void add(int x,int y,int w)
{
e[++cnt].nxt=head[x];
e[cnt].to=y;
e[cnt].w=w;
head[x]=cnt;
}
pair<int,int> pls(pair<int,int> a,pair<int,int> b){return make_pair(a.first+b.first,a.second+b.second);}
pair<int,int> min(pair<int,int> a,pair<int,int> b){return(a.first==b.first)?((a.second<b.second)?a:b):((a.first<b.first)?a:b);}
void dfs(int x,int fa,int w)
{
pair<int,int> w1=make_pair(inf,inf);
pair<int,int> w2=make_pair(0,0);
for(int i=head[x];i;i=e[i].nxt)
if(e[i].to!=fa)
{
dfs(e[i].to,x,e[i].w);
pair<int,int> flag1=min(pls(w1,dp[0][e[i].to]),pls(w2,dp[1][e[i].to]));
pair<int,int> flag2=min(pls(w1,dp[1][e[i].to]),pls(w2,dp[0][e[i].to]));
w1=flag1;
w2=flag2;
}
if(w==1)dp[0][x]=make_pair(inf,inf);
else dp[0][x]=min(make_pair(w1.first+1,w1.second),w2);
if(!w)dp[1][x]=make_pair(inf,inf);
else dp[1][x]=min(make_pair(w1.first,w1.second+1),make_pair(w2.first+1,w2.second+1));
}
int main()
{
scanf("%d",&n);
for(int i=1;i<n;i++)
{
int a,b,c,d;
scanf("%d%d%d%d",&a,&b,&c,&d);
if(d==2){add(a,b,2);add(b,a,2);}
else {add(a,b,c!=d);add(b,a,c!=d);}
}
dfs(1,0,2);
printf("%d %d\n",dp[0][1].first>>1,dp[0][1].second);
return 0;
}
rp++