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

猜你喜欢

转载自www.cnblogs.com/ppprseter/p/10087326.html