QTREE6 - Query on a tree VI
题目描述
给你一棵\(n\)个点的树,编号\(1\)~\(n\)。每个点可以是黑色,可以是白色。初始时所有点都是黑色。下面有两种操作请你操作给我们看:
0 u:询问有多少个节点v满足路径u到v上所有节点(包括)都拥有相同的颜色
1 u:翻转u的颜色
输入格式
一行一个整数\(n\)
接下来\(n-1\)行,每行两个整数表示一条边
接下来一行一个整数\(m\)表示操作次数
接下来\(m\)行,每行两个整数分别表示操作类型和被操作节点
输出格式
对每个询问操作输出相应的结果
暴力分两棵树LCT维护会菊花树卡。
考虑把点权放到边上,这样的好处是当维护联通性时,只会改一条边。
把树搞成两颗,分别用LCT维护,一个点在激活在对应颜色的树的头顶边。
我们要资瓷询问子树信息,维护方法可以先做“大融合”
然后发现为了维护树的形态,我们不可以进行换根。
扫描二维码关注公众号,回复:
4421828 查看本文章
那么就要根据修改的形式自己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