第一行一個整數$n$,表明點數
接下來$n-1$行,每行三個數$x,y,z$,表明點$i$與$x$之間有一條邊,若$y$爲$0$表明初始爲白色,不然爲黑色,若$z$爲$0$表明不對最終顏色作要求,不然表明要求爲黑色。html
達到目的的最少操做多少次數。c++
樣例輸入:算法
7
1 0 1
1 1 1
2 0 1
2 0 1
3 1 1
3 0 1spa
樣例輸出:3d
3htm
對於$30\%$的數據,全部的$x$等於$1$。
對於$70\%$的數據,全部邊最終都必須爲黑色
對於$100\%$的數據,$n\leqslant 1,000,000$。blog
先看數據範圍,$n\leqslant 1,000,000$(注意是一百萬,不是十萬,可能只有我數不清幾個$0$了吧?),這隻能容許咱們$\Theta(n)$。get
$70\%$算法:it
仍是先從部分分下手,先來考慮$70\%$的數據,全部便最終都必須爲黑色,考慮貪心。class
比方說有下面這樣一條鏈:
咱們能夠選擇翻轉$1\sim 3$和$4\sim 5$,也能夠選擇先翻轉$1\sim 5$再將$3\sim 4$翻轉回來,可是都須要兩步,因此咱們能夠貪心的掃每一條鏈,直到掃到一條黑邊爲止,把這中間的都翻轉便可。
那麼如今來考慮許多邊連向一個點的狀況:
比方說上面這張圖,一共有三個白邊連向點$1$,你可能首先會下意識的覺得須要翻轉三次(聰明的你也可能沒有),可是仔細一想,咱們能夠把這其中任意兩個翻轉合併,如翻轉$2\sim 1\sim 4$這條路徑,而後再翻轉$1\sim 7$這條路徑以達到目的。
那麼不妨這樣講,對於多條邊連向一個點的狀況,其所需的翻轉次數即爲$\left \lceil \frac{黑邊個數}{2} \right \rceil$。
時間複雜度:$\Theta(n)$。
指望得分:$70$分。
實際得分:$60$分。
$100\%$算法:
顯然對於一道$T1$來講,咱們應該$A$掉它。
發現每條邊只會被要求爲黑色,或者是任意顏色,因此在來貪心。
對於任意顏色,咱們能夠無視它,這不太好想,但仔細一想也是對的,我也不知道該怎麼解釋了,本身體會吧?因此咱們能夠把這種邊縮掉,個人方法是用一個相似並查集思想的東西,可是比並查集簡單的多。
時間複雜度:$\Theta(n)$。
指望得分:$100$分。
實際得分:$100$分。
#include<bits/stdc++.h>
using namespace std;
struct rec{int nxt,to,w;}e[2000001];
int head[1000001],cnt=1;
int n;
bool vis[2000001];
int fa[1000001];
int ans;
void add(int x,int y,int w)
{
e[++cnt].nxt=head[x];
e[cnt].to=y;
e[cnt].w=w;
head[x]=cnt;
}
void dfs(int x)
{
for(int i=head[x];i;i=e[i].nxt)
if(!vis[i]&&!e[i].w)
{
vis[i]=vis[i^1]=1;
dfs(e[i].to);
return;
}
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)fa[i]=i;
for(int i=2;i<=n;i++)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
if(!z)fa[i]=fa[x];
else
{
add(i,fa[x],y);
add(fa[x],i,y);
}
}
for(int x=1;x<=n;x++)
{
int sum=0;
for(int i=head[x];i;i=e[i].nxt)
if(!vis[i]&&!e[i].w)
{
vis[i]=vis[i^1]=1;
dfs(e[i].to);
sum++;
}
if(sum&1)ans+=sum/2+1;
else ans+=sum/2;
}
printf("%d",ans);
return 0;
}
rp++