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
轉載于:https://www.cnblogs.com/butterflydew/p/10087326.html