1. 程式人生 > 實用技巧 >虎(思維題+樹結構)

虎(思維題+樹結構)

OvO

  • 貪心

  • 對於一個節點來說,顯然是對著的可以一條線連下來。所以偶數個的就正好是\(\frac{son}{2}\).
    然後對於奇數個的,那就是讓偶數個先配上,剩下的一個向上傳,這個是不影響父節點的。
    最後就是連邊的時候,對於已經染成黑色的就不必再建邊了。因為動一個已經黑色的不會更優。
    對於最後顏色沒有要求的,這條邊就沒什麼用處,但是需要它來連線其他邊以達到更優解,所以用一種並查集的思想把這條邊縮起來,讓它的兒子和它的父親相連即可。

if(!y&&z)f[i]=to[x]; 
if(!z)to[i]=to[x];
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=1e6+1;
int n;
int f[maxn],to[maxn];
bool vis[maxn];
int ANS=0;
int head[maxn],len=0;
struct E{int to,next,w;}e[maxn<<1];
void A(int x,int y){e[++len].to=y;e[len].next=head[x];head[x]=len;}
int Find(int x){return f[x]==x?x:f[x]=Find(f[x]);}
void Dfs(int u){    
    vis[u]=1;
    int cnt=0;
    for(int i=head[u];i;i=e[i].next){
        int v=e[i].to;
        cnt++; 
        //printf("%d %d %d\n",u,v,cnt);
        Dfs(v); 
    }//printf("OvO %d %d\n",u,cnt);
    if(cnt&1){
        if(f[u])ANS+=(cnt-1)/2;
        else ANS+=(cnt+1)/2; 
    }
    else {
        ANS+=cnt/2; 
    }
}
int main(){
    freopen("tiger.in","r",stdin);
    freopen("tiger.out","w",stdout);
    scanf("%d",&n);
    for(int i=1;i<=n;i++)to[i]=i;
    for(int i=2;i<=n;i++){
        int x,y,z;scanf("%d%d%d",&x,&y,&z);
        if(!y&&z)f[i]=to[x]; 
        if(!z)to[i]=to[x];
    }//for(int i=1;i<=n;i++)printf("%d fa=%d\n",i,f[i]);
    for(int i=1;i<=n;i++){
        if(f[i])A(f[i],i);
    }for(int i=1;i<=n;i++){
        if(!vis[i]){
            Dfs(i);
        }
    }printf("%d\n",ANS);
    return 0;
}