树和森林
题解
很好骗分的一道题,有人就在场上骗到了90pts,例子就是我。
我们可以先来看一看部分分。
14pts:我们直接枚举两个连通块上相连的点,的算法。
20pts:很容易发现,在两个联通块上互相相连的点是谁并不重要,记一个点到块上每个点的路径长度总和为,记一个联通块中最大的值为,答案就是,其中表示这个连通块自身的贡献,值可以用一个换根dp来求出,时间复杂度。
30pts:再将三个联通块中的中间的连通块与其它连通块相连接的点枚举,答案为
其中点为中间块。由于可以通过倍增求出,时间复杂度。
70pts:对于子任务2,我们可以通过树形dp快速的求出,只用判断该节点与其子节点是否相连即可,分别存储该节点与其儿子连边为奇数或是偶数,跑一遍dfs。时间复杂度。
90pts:容易证明,对于一棵树,要么其无法满足拆分条件,要么有唯一解。因为叶节点的奇偶性是固定的,故其父亲节点的来连边状况也是固定的,若根节点符合条件则有唯一解,否则无解,用70pts的做法可以求出。于是笔者就得到了90pts。
100pts:我们发现,在30pts的做法中,只有一项不是固定的,其它都可以预处理出来,我们只用考虑如何求出最大的。我们可以将拆成。于是,原式就成了。我们可以在dfs的过程中,对于每个节点求出它作为lca时上式的最大值,可以通过树形dp来维护。
源码
笔者代码有些冗长。
#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
#include<map>
#include<set>
using namespace std;
#define MAXN 100005
typedef long long LL;
typedef unsigned long long uLL;
const int INF=0x7f7f7f7f;
typedef pair<int,int> pii;
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
template<typename _T>
void read(_T &x){
_T f=1;x=0;char s=getchar();
while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
x*=f;
}
int n,m,rt[5],sz[5],dep[MAXN];
LL mf[MAXN],sumf[MAXN],f[MAXN],g[MAXN],siz[MAXN];
LL mx1[MAXN],mx2[MAXN],mx;
int dp[MAXN][2],fi[MAXN],sta[MAXN],stak,ff[MAXN][20];
bool col[MAXN],dw[MAXN][2];char maze[MAXN];
int belong[MAXN],cnt,head[MAXN],tot;
struct edge{int to,nxt,id;}e[MAXN<<1];
void addEdge(int u,int v,int i){e[++tot]=(edge){v,head[u],i};head[u]=tot;}
void dfs1(int u,int fa){
g[u]=0;sz[belong[u]]++;siz[u]=1;dep[u]=dep[fa]+1;
ff[u][0]=fa;for(int i=1;i<19;i++)ff[u][i]=ff[ff[u][i-1]][i-1];
for(int i=head[u];i;i=e[i].nxt){
int v=e[i].to;if(v==fa)continue;
belong[v]=cnt;dfs1(v,u);
siz[u]+=siz[v];g[u]+=g[v]+siz[v];
}
}
void dfs2(int u,int fa){
f[u]=g[u];
for(int i=head[u];i;i=e[i].nxt){
int v=e[i].to;if(v==fa)continue;
g[u]-=g[v]+siz[v];siz[u]-=siz[v];
g[v]+=g[u]+siz[u];siz[v]+=siz[u];
dfs2(v,u);
siz[v]-=siz[u];g[v]-=g[u]+siz[u];
siz[u]+=siz[v];g[u]+=g[v]+siz[v];
}
}
void dfs3(int u,int fa){
int res=0,md=INF,sum=0,mdd=-1;
if(!head[u]){dp[u][0]=0;dp[u][1]=-INF;return ;}
for(int i=head[u];i;i=e[i].nxt){
int v=e[i].to;if(v==fa)continue;
fi[v]=e[i].id;dfs3(v,u);
if(col[v]==1){
res+=max(dp[v][1],dp[v][0]+1);
if(dp[v][0]+1>=dp[v][1])sum++;
if(dp[v][1]>=0&&dp[v][0]>=0){
if(Fabs(dp[v][1]-dp[v][0]-1)<md);
md=Fabs(dp[v][1]-dp[v][0]-1),mdd=v;
}
}
else{
res+=max(dp[v][0],dp[v][1]+1);
if(dp[v][1]+1>=dp[v][0])sum++;
if(dp[v][0]>=0&&dp[v][1]>=0){
if(Fabs(dp[v][1]-dp[v][0]-1)<md)
md=Fabs(dp[v][0]-dp[v][1]-1),mdd=v;
}
}
}
if(sum&1)dp[u][1]=res,dp[u][0]=(md<=res?res-md:-INF);
else dp[u][0]=res,dp[u][1]=(md<=res?res-md:-INF);
for(int i=head[u];i;i=e[i].nxt){
int v=e[i].to;if(v==fa)continue;
if(col[v]==1){
if(dp[v][0]+1>=dp[v][1]){
dw[v][sum&1]=1;
if(mdd!=v)dw[v][(sum&1)^1]=1;
}
else if(mdd==v)dw[v][(sum&1)^1]=1;
}
else{
if(dp[v][1]+1>=dp[v][0]){
dw[v][sum&1]=1;
if(mdd!=v)dw[v][(sum&1)^1]=1;
}
else if(mdd==v)dw[v][(sum&1)^1]=1;
}
}
}
int lca(int a,int b){
if(dep[a]>dep[b])swap(a,b);
for(int i=18;i>=0;i--)if(dep[ff[b][i]]>=dep[a])b=ff[b][i];
if(a==b)return a;
for(int i=18;i>=0;i--)if(ff[a][i]!=ff[b][i])a=ff[a][i],b=ff[b][i];
return ff[a][0];
}
void dfs4(int u,int fa,int s){
for(int i=head[u];i;i=e[i].nxt){
int v=e[i].to;if(v==fa)continue;
if(dw[v][s])sta[++stak]=fi[v],dfs4(v,u,col[v]^1);
else dfs4(v,u,col[v]);
}
}
void dfs5(int u,int fa,int a,int b){
mx1[u]=f[u]*a;mx2[u]=f[u]*b;mx=max(mx,mx1[u]+mx2[u]);
for(int i=head[u];i;i=e[i].nxt){
int v=e[i].to;if(v==fa)continue;
dfs5(v,u,a,b);LL c=1ll*a*b;
mx=max(mx,mx1[u]+mx2[v]+c);
mx=max(mx,mx2[u]+mx1[v]+c);
mx1[u]=max(mx1[u],mx1[v]+c);
mx2[u]=max(mx2[u],mx2[v]+c);
}
}
LL getmx(int rt,int a,int b){mx=0;dfs5(rt,0,a,b);return mx;}
signed main(){
//freopen("lct.in","r",stdin);
//freopen("lct.out","w",stdout);
read(n);read(m);scanf("\n%s",maze+1);
for(int i=1;i<=n;i++)col[i]=(maze[i]=='B');
for(int i=1;i<=m;i++){
int u,v;read(u);read(v);
addEdge(u,v,i);addEdge(v,u,i);
}
for(int i=1;i<=n;i++)
if(!belong[i]){
belong[i]=++cnt,rt[cnt]=i;
dfs1(i,0);dfs2(i,0);
}
for(int i=1;i<=n;i++)mf[belong[i]]=max(mf[belong[i]],f[i]);
for(int i=1;i<=n;i++)sumf[belong[i]]+=1ll*f[i];
for(int i=1;i<=cnt;i++)sumf[i]/=2LL;
if(cnt==2)printf("%lld\n",sumf[1]+sumf[2]+1ll*mf[1]*sz[2]+1ll*mf[2]*sz[1]+1ll*sz[1]*sz[2]);
else{
LL res=0;
res=max(res,(mf[2]+sz[2])*(n-sz[2])+(mf[3]+sz[3])*(n-sz[3])+getmx(rt[1],sz[2],sz[3]));
res=max(res,(mf[1]+sz[1])*(n-sz[1])+(mf[2]+sz[2])*(n-sz[2])+getmx(rt[3],sz[1],sz[2]));
res=max(res,(mf[1]+sz[1])*(n-sz[1])+(mf[3]+sz[3])*(n-sz[3])+getmx(rt[2],sz[1],sz[3]));
printf("%lld\n",res+sumf[1]+sumf[2]+sumf[3]);
}
for(int i=1;i<=cnt;i++)dfs3(rt[i],0);int ans=0;
for(int i=1;i<=cnt;i++){
if(dp[rt[i]][col[rt[i]]]<0)ans=-1;
if(ans<0)continue;
ans+=dp[rt[i]][col[rt[i]]];
}
printf("%d\n",ans);if(ans<0)return 0;
for(int i=1;i<=cnt;i++)dfs4(rt[i],0,col[rt[i]]);
sort(sta+1,sta+stak+1);
for(int i=1;i<=stak;i++)printf("%d ",sta[i]);puts("");
return 0;
}