联考day7 C. 树和森林 树形DP
题目描述
样例
样例输入
8 5
BBWWWBBW
1 2
2 3
4 5
6 7
7 8
样例输出
84
2
1 4
样例解释
分析
首先,我们要预处理出一个点到该联通块内所有点的距离之和 \(f\)
这个东西用换根 \(DP\) 搞一下就可以了
那么这个联通块内所有点对的距离之和就是这个联通块所有点的 \(f\) 值之和除以 \(2\)
除以 \(2\) 是因为点对是无序的
对于子任务一:
当联通块的个数为 \(2\) 时,两个联通块内的贡献我们已经考虑了
我们需要考虑的就是跨过联通块的贡献
我们设从联通块 \(1\) 中选择的点为 \(a\),从联通块 \(2\) 中选择的点为 \(b\) ,联通块的大小是 \(cnt\)
那么贡献就是 \((f[a]+cnt[1])*(n-cnt[1])+cnt[1]*f[b]\)
前半部分统计的是 \(1\) 联通块经过 \((a,b)\) 这条边的贡献
后半部分统计的是 \(2\) 联通块对 \(1\) 联通块的贡献
显然,我们需要把两个联通块内 \(f\) 值最大的点连接起来
当联通块的个数为 \(3\) 时,我们可以枚举哪个联通块在中间
设第一个联通块与第二个联通块通过 \((x, y)\) 相连
第二个联通块与第三个联通块通过 \((u, v)\) 相连。
则联通块与联通块之间的贡献为:
\((f[x]+cnt[1])(n−cnt[1])+(f[v]+cnt[3])(n−cnt[3])+cnt[1]f[y]+cnt[3]f[u]+dis(y,u)cnt[1]cnt[3]\)
其中 \(dis\) 代表两点间的距离
那么 \(x\), \(v\) 应该是联通块 \(1\) 和联通块 \(3\) 中 \(f\) 最大的点。
对于联通块 \(2\),我们只要求出 \(cnt[1]f[y]+cnt[3]f[u]+dis(y,u)cnt[1]cnt[3]\) 的最大值即可,这个
可以通过 \(dp\) 实现
我们分别开两个数组存储当前 \(cnt[1]f[y]\) 和 \(cnt[3]f[u]\)的最大值
自底向上 \(dp\)
对于后面的 \(dis\) 值,我们只需要在向上递归是加一个 \(cnt[1]cnt[3]\) 即可
对于子任务二:
考虑一棵树内的所有不满足条件的点。如果有奇数个这样的点,那么无解,否则一定有解,
并且唯一。
我们要使这些点变成合法的,就需要对它们进行两两匹配,然后改变每一对点路径上所有
边的存在情况。
那么,如果一条边两侧的连通块内有奇数个这样的点,这个边的状态就一定被改变了奇数
次,因此它被删掉了;否则它没有被删掉。
总复杂度 \(O(n)\)
代码
#include<cstdio>
#include<cstring>
#include<iostream>
#define rg register
inline int read(){
rg int x=0,fh=1;
rg char ch=getchar();
while(ch<'0' || ch>'9'){
if(ch=='-') fh=-1;
ch=getchar();
}
while(ch>='0' && ch<='9'){
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*fh;
}
const int maxn=1e6+5;
int n,m,sl,h[maxn],tot=1,rt1,rt2,rt3,siz[maxn],cnt[maxn],vis[maxn];
struct asd{
int to,nxt;
}b[maxn];
void ad(int aa,int bb){
b[tot].to=bb;
b[tot].nxt=h[aa];
h[aa]=tot++;
}
char s[maxn];
long long f[maxn],g[maxn];
void dfs(int rt,int now,int fa){
siz[now]=1;
vis[now]=rt;
cnt[rt]++;
for(rg int i=h[now];i!=-1;i=b[i].nxt){
rg int u=b[i].to;
if(u==fa) continue;
dfs(rt,u,now);
siz[now]+=siz[u];
g[now]+=g[u]+siz[u];
}
}
void dfs2(int rt,int now,int fa){
if(now==rt)f[now]=g[now];
for(rg int i=h[now];i!=-1;i=b[i].nxt){
rg int u=b[i].to;
if(u==fa) continue;
f[u]=f[now]+cnt[rt]-siz[u]-siz[u];
dfs2(rt,u,now);
}
}
int jl,mmax,A,B,C,D;
void solve1(){
rg long long ans=0;
for(rg int i=1;i<=n;i++){
if(vis[i]==0){
dfs(i,i,0);
if(!rt1) rt1=i;
else rt2=i;
}
}
dfs2(rt1,rt1,0);
dfs2(rt2,rt2,0);
for(rg int i=1;i<=n;i++){
ans+=f[i];
}
ans/=2;
mmax=-1,jl=0;
for(rg int i=1;i<=n;i++){
if(vis[i]==rt1){
if(f[i]>mmax){
mmax=f[i];
jl=i;
}
}
}
A=jl;
mmax=-1,jl=0;
for(rg int i=1;i<=n;i++){
if(vis[i]==rt2){
if(f[i]>mmax){
mmax=f[i];
jl=i;
}
}
}
B=jl;
ans+=(f[A]+cnt[rt1])*(n-cnt[rt1])+cnt[rt1]*f[B];
printf("%lld\n",ans);
}
long long maxb[maxn],maxc[maxn],haha=0;
void dfs5(int now,int fa,int cntl,int cntr){
maxb[now]=cntl*f[now];
maxc[now]=cntr*f[now];
for(rg int i=h[now];i!=-1;i=b[i].nxt){
rg int u=b[i].to;
if(u==fa) continue;
dfs5(u,now,cntl,cntr);
haha=std::max(haha,maxb[now]+maxc[u]+1LL*cntl*cntr);
haha=std::max(haha,maxc[now]+maxb[u]+1LL*cntl*cntr);
maxb[now]=std::max(maxb[u]+1LL*cntl*cntr,maxb[now]);
maxc[now]=std::max(maxc[u]+1LL*cntl*cntr,maxc[now]);
}
}
long long js(int l,int mids,int r){
memset(maxb,0,sizeof(maxb));
memset(maxc,0,sizeof(maxc));
rg long long jla=0,jld=0;
haha=0;
for(rg int i=1;i<=n;i++){
if(vis[i]==l){
if(f[i]>jla) jla=f[i];
}
if(vis[i]==r){
if(f[i]>jld) jld=f[i];
}
}
dfs5(mids,0,cnt[l],cnt[r]);
haha+=(jla+cnt[l])*(n-cnt[l])+(jld+cnt[r])*(n-cnt[r]);
return haha;
}
void solve2(){
rg long long ans=0;
for(rg int i=1;i<=n;i++){
if(vis[i]==0){
dfs(i,i,0);
if(!rt1) rt1=i;
else if(!rt2)rt2=i;
else rt3=i;
}
}
dfs2(rt1,rt1,0);
dfs2(rt2,rt2,0);
dfs2(rt3,rt3,0);
for(rg int i=1;i<=n;i++){
ans+=f[i];
}
ans/=2;
rg long long nans=0;
nans=std::max(nans,js(rt1,rt2,rt3));
nans=std::max(nans,js(rt1,rt3,rt2));
nans=std::max(nans,js(rt2,rt1,rt3));
ans+=nans;
printf("%lld\n",ans);
}
int sta[maxn],tp,du[maxn],num[maxn];
bool kil[maxn];
void dfs3(int now,int fa){
for(rg int i=h[now];i!=-1;i=b[i].nxt){
rg int u=b[i].to;
if(u==fa) continue;
dfs3(u,now);
num[now]+=num[u];
}
}
void dfs4(int rt,int now,int fa){
for(rg int i=h[now];i!=-1;i=b[i].nxt){
rg int u=b[i].to;
if(u==fa) continue;
dfs4(rt,u,now);
if((num[rt]-num[u])&1 && num[u]&1){
kil[i]=1;
}
}
}
void solve3(){
for(rg int i=1;i<=n;i++){
if(s[i]=='B'){
if(du[i]%2==0) num[i]=1;
} else {
if(du[i]&1) num[i]=1;
}
}
if(sl==2){
dfs3(rt1,0);
dfs3(rt2,0);
if(num[rt1]&1 || num[rt2]&1){
printf("-1\n");
return;
}
dfs4(rt1,rt1,0);
dfs4(rt2,rt2,0);
} else {
dfs3(rt1,0);
dfs3(rt2,0);
dfs3(rt3,0);
if(num[rt1]&1 || num[rt2]&1 || num[rt3]&1){
printf("-1\n");
return;
}
dfs4(rt1,rt1,0);
dfs4(rt2,rt2,0);
dfs4(rt3,rt3,0);
}
for(rg int i=1;i<tot;i+=2){
if(kil[i] || kil[i+1]) continue;
sta[++tp]=(i+1)/2;
}
printf("%d\n",tp);
for(rg int i=1;i<=tp;i++){
printf("%d ",sta[i]);
}
printf("\n");
}
int main(){
freopen("lct.in","r",stdin);
freopen("lct.out","w",stdout);
memset(h,-1,sizeof(h));
n=read(),m=read();
sl=(n-m);
scanf("%s",s+1);
rg int aa,bb;
for(rg int i=1;i<=m;i++){
aa=read(),bb=read();
ad(aa,bb);
ad(bb,aa);
du[aa]++;
du[bb]++;
}
if(sl==2){
solve1();
} else {
solve2();
}
solve3();
return 0;
}
联考day7 C. 树和森林 树形DP的更多相关文章
- LOJ3053 十二省联考2019 希望 容斥、树形DP、长链剖分
传送门 官方题解其实讲的挺清楚了,就是锅有点多-- 一些有启发性的部分分 L=N 一个经典(反正我是不会)的容斥:最后的答案=对于每个点能够以它作为集合点的方案数-对于每条边能够以其两个端点作为集合点 ...
- 可恶!学了这么久的LCA,联考的题目却是LCA+树形DP!!!可恶|!!!这几天想学学树形DP吧!先来一道入门题HDU 1520 Anniversary party
题目描述 某大学有N个职员,编号为1~N.他们之间有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司.现在有个周年庆宴会,宴会每邀请来一个职员都会增加一定的快乐指数Ri, ...
- P3748 [六省联考2017]摧毁“树状图”
传送门 显然是可以树形 $dp$ 的 对每个节点维护以下 $5$ 个东西 $1.$ 从当前节点出发往下的链的最大贡献 $2.$ 节点子树内不经过本身的路径最大贡献 $3.$ 节点子树内经过本身的路径的 ...
- 2014 Super Training #9 E Destroy --树的直径+树形DP
原题: ZOJ 3684 http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3684 题意: 给你一棵树,树的根是树的中心(到其 ...
- (中等) HDU 5293 Tree chain problem,树链剖分+树形DP。
Problem Description Coco has a tree, whose vertices are conveniently labeled by 1,2,…,n.There are ...
- bzoj 4871: [Shoi2017]摧毁“树状图” [树形DP]
4871: [Shoi2017]摧毁"树状图" 题意:一颗无向树,选两条边不重复的路径,删去选择的点和路径剩下一些cc,求最多cc数. update 5.1 : 刚刚发现bzoj上 ...
- BZOJ1758[Wc2010]重建计划——分数规划+长链剖分+线段树+二分答案+树形DP
题目描述 输入 第一行包含一个正整数N,表示X国的城市个数. 第二行包含两个正整数L和U,表示政策要求的第一期重建方案中修建道路数的上下限 接下来的N-1行描述重建小组的原有方案,每行三个正整数Ai, ...
- 算法笔记--树的直径 && 树形dp && 虚树 && 树分治 && 树上差分 && 树链剖分
树的直径: 利用了树的直径的一个性质:距某个点最远的叶子节点一定是树的某一条直径的端点. 先从任意一顶点a出发,bfs找到离它最远的一个叶子顶点b,然后再从b出发bfs找到离b最远的顶点c,那么b和c ...
- 【bzoj5123】[Lydsy12月赛]线段树的匹配 树形dp+记忆化搜索
题目描述 求一棵 $[1,n]$ 的线段树的最大匹配数目与方案数. $n\le 10^{18}$ 题解 树形dp+记忆化搜索 设 $f[l][r]$ 表示根节点为 $[l,r]$ 的线段树,匹配选择根 ...
随机推荐
- noSql 的应用场景简述
选型一定要结合实际情况而不是照本宣科,比如: 企业发展之初,明明一个关系型数据库就能搞定且支撑一年的架构,搞一套大而全的技术方案出来 有一些数据条件查询多,更适合使用ElasticSearch做存储降 ...
- Elasticsearch数据库 | Elasticsearch-7.5.0应用基础实战
Elasticsearch 是一个可用于分布式以及符合RESTful 风格的搜索和数据分析引擎.-- Elastic Stack 官网 关于Elasticsearch的"爱恨情仇" ...
- 《Head First 设计模式》:代理模式
正文 一.定义 代理模式为另一个对象提供一个替身或占位符以控制对这个对象的访问. 要点: 代理模式为一个对象创建了代理对象,让代理对象控制对该对象的访问.被代理的对象可以是远程的对象.创建开销大的对象 ...
- Redis小记(二)
1.redis数据库 redis数据库属于内存数据库,若不将数据存到磁盘中,服务器进程退出,数据也会消失 redis所有数据库都保存在redisServer结构的db数组中,db数组的每一项都是一个r ...
- Centos-shell-特殊字符
shell 通配符 # 注意完全不同于正则,类似正则 * 任意至少一个字符 ? 任意一个字符 [] []中任意一个字符,相关字符集a-z A-Z 0-9 shell 重定向 # 重新指定系统标准输 ...
- 【小白学PyTorch】18 TF2构建自定义模型
[机器学习炼丹术]的炼丹总群已经快满了,要加入的快联系炼丹兄WX:cyx645016617 参考目录: 目录 1 创建自定义网络层 2 创建一个完整的CNN 2.1 keras.Model vs ke ...
- 整理requests和正则表达式爬取猫眼Top100中遇到的问题及解决方案
最近看崔庆才老师的爬虫课程,第一个实战课程是requests和正则表达式爬取猫眼电影Top100榜单.虽然理解崔老师每一步代码的实现过程,但自己敲代码的时候还是遇到了不少问题: 问题1:获取respo ...
- 引用类型之Array(二)
操作方法 concat( ) concat() 方法用于连接两个或多个数组. 该方法不会改变现有的数组,而仅仅会返回被连接数组的一个副本. 语法 arrayObject.concat(arrayX,a ...
- 在nginx下导出数据库数据
首先上干货 解决问题 set_time_limit(0); //设置脚本运行时间为不限制 因为php脚本默认时间为30秒 ini_set('memory_limit', -1); //取消脚本运行内存 ...
- Makefile-3-书写规则
目录 前言 概念 Chapter 3:书写规则 3.3 在规则中使用通配符 3.4 文件搜索 3.8 自动生成依赖性 原理 * 直接解析例子 ** sed 命令 参考 书籍 前言 本笔记主要记录Mak ...