1. 程式人生 > >QTREE6 - Query on a tree VI 解題報告

QTREE6 - Query on a tree VI 解題報告

QTREE6 - Query on a tree VI

題目描述

給你一棵\(n\)個點的樹,編號\(1\)~\(n\)。每個點可以是黑色,可以是白色。初始時所有點都是黑色。下面有兩種操作請你操作給我們看:

0 u:詢問有多少個節點v滿足路徑u到v上所有節點(包括)都擁有相同的顏色
1 u:翻轉u的顏色

輸入格式

一行一個整數\(n\)

接下來\(n-1\)行,每行兩個整數表示一條邊

接下來一行一個整數\(m\)表示操作次數

接下來\(m\)行,每行兩個整數分別表示操作型別和被操作節點

輸出格式

對每個詢問操作輸出相應的結果


暴力分兩棵樹LCT維護會菊花樹卡。

考慮把點權放到邊上,這樣的好處是當維護聯通性時,只會改一條邊。

把樹搞成兩顆,分別用LCT維護,一個點在啟用在對應顏色的樹的頭頂邊。

我們要資瓷詢問子樹資訊,維護方法可以先做“大融合”

然後發現為了維護樹的形態,我們不可以進行換根。

那麼就要根據修改的形式自己yy\(link,cat,qurey\)那些東西了。


Code:

#include <cstdio>
#include <cstring>
const int N=502;
int head[N],to[N<<1],Next[N<<1],cnt;
void add(int u,int v)
{
    to[++cnt]=v,Next[cnt]=head[u],head[u]=cnt;
}
int dp[N][2];
int max(int x,int y){return x>y?x:y;}
void dfs(int now,int fa,int da,int db)
{
    int s1=0,s2=-N,ison=0;
    for(int v,i=head[now];i;i=Next[i])
        if((v=to[i])!=fa)
        {
            dfs(v,now,da,db);
            s1+=max(dp[v][0],dp[v][1]);
            ison=1;
        }
    for(int v,i=head[now];i;i=Next[i])
        if((v=to[i])!=fa)
            s2=max(s2,s1-max(dp[v][0],dp[v][1])+dp[v][0]);
    dp[now][0]=s1,dp[now][1]=s2+ison;
    if(now==da||now==db) dp[now][1]=dp[now][0],dp[now][0]=-N;
}
int cal(int a,int b)
{
    memset(dp,0,sizeof(dp));
    dfs(1,0,a,b);
    return max(dp[1][0],dp[1][1])+(a>0);
}
int n;
int main()
{
    scanf("%d",&n);
    for(int u,v,i=1;i<n;i++)
    {
        scanf("%d%d",&u,&v);
        add(u,v),add(v,u);
    }
    int a=cal(0,0),ans=0;
    for(int i=1;i<=n;i++)
        for(int j=i+1;j<=n;j++)
        {
            int d=cal(i,j);
            if(d==a+1)
                ++ans;
        }
    printf("%d\n",ans);
    return 0;
}

2018.12.8