【HNOI】 lct tree-dp

  【题目描述】给定2-3颗树,每个边的边权为1,解决以下独立的问题。

    现在通过连接若干遍使得图为连通图,并且Σdis(x,y)最大,x,y只算一次。

    每个点为黑点或者白点,现在需要删除一些边,使得图中的黑点度数为奇数,白点为偶数,要求删除的边最多。

  【数据范围】 100% n<=10^5

  首先我们来解决第一问,因为每加一条边就可能使得若干点到其他点的距离变小,那么我们需要加尽量少的边来使得图连通。

  设dis_[x]为x在x所在子树中,x到其他所有点的距离,这个我们可以通过设dis[x]表示x到x子树中所有点的距离和来由父节点转移得到。

  那么答案可以分为两部分,分别为树中的点对距离和跨树的点对距离,前一个问题比较容易,可以通过dis_[x]或者计算每条边被经过的次数来求出。

  那么对于两颗树的情况,我们就需要连接这两棵树中dis值最大的两个点,假设为x,y。这样答案就是      dis[x]*size[tree_y]+dis[y]*size[tree_x]+size[tree_x]*size[tree_y],这个由连接的那条边的被经过次数可以得出。

  那么现在考虑三棵树的情况,我们需要枚举中间的树,这样左右两棵树肯定连接dis最大的点,中间的连接的则不确定,我们可以列出来整个答案的表达式,设左面的树和中间的树通过x,y点连通,中间的点和右面的树通过u,v点连接,设三棵树的size为size[1],size[2],size[3],y与u点的距离为d[y][u],那么答案就是size[1]*dis_[y]+size[2]*dis_[x]+size[1]*size[2]+size[3]*dis_[u]+size[2]*dis_[v]+size[1]*dis_[v]+size[3]*dis_[u]+size[1]*size[3]*(d[y][u]+2)

  我们可以发现,这个中与y,u点有关的式子可以写成a*dis_[y]+b*dis_[u]+c*d[u][v]的形式,其中a,b,c为常数,那么对于这个我们就可以用tree-dp搞出来,记录点x的子树中dis_[p]+(d[x][p]+1)*c的最大值,然后不断的更新答案就可以了。

  第二问比较简单,我们可以贪心的来想,对于一棵树,我们从叶子节点开始,因为叶子节点的度数为1,那么我们只需要判断叶子节点的颜色,就可以判断这个点和其父节点的边是否可以删掉。

  反思:开始写tree-dp维护中间树的值的时候没有考虑到一些特殊情况,比如连接的y,u点其中一点是另一点的祖先,还有开始觉得如果中间的树选择两个点肯定不能是同一点,所以边界就处理的不是特别好,但是可能会有某些点单独构成树,这样的话就必须连接同一个点。第二问还是比较容易写的。

//By BLADEVIL
#include <cstdio>
#include <cstring>
#include <algorithm>
#define maxn 100010
#define LL long longusing namespace std;LL n,m,l;
LL a[maxn],pre[maxn<<1],other[maxn<<1],last[maxn],col[maxn],rot[4],num[maxn<<1],flag[maxn];
LL dis_[maxn],dis[maxn],size[maxn],ans[maxn],ANS[4],max_a[maxn],max_b[maxn],cnt[maxn];void connect(LL x,LL y,LL z) {pre[++l]=last[x];last[x]=l;other[l]=y;num[l]=z;
}void paint(LL x,LL fa,LL c) {col[x]=c;for (LL p=last[x];p;p=pre[p]) {if (other[p]==fa) continue;paint(other[p],x,c);}
}void make_dis(LL x,LL fa) {dis[x]=0; size[x]=1;for (LL p=last[x];p;p=pre[p]) {if (other[p]==fa) continue;make_dis(other[p],x);dis[x]+=dis[other[p]]+size[other[p]];size[x]+=size[other[p]];}
}void make_dis_(LL x,LL fa,LL s) {if (fa!=-1) dis_[x]=dis_[fa]-size[x]-dis[x]+s-size[x]+dis[x]; else dis_[x]=dis[x];for (LL p=last[x];p;p=pre[p]) {if (other[p]==fa) continue;make_dis_(other[p],x,s);}
}void calc(LL x,LL fa,LL s) {for (LL p=last[x];p;p=pre[p]) {if (other[p]==fa) continue;ANS[col[x]]+=size[other[p]]*(s-size[other[p]]);calc(other[p],x,s);}
}void dp(LL x,LL fa,LL a,LL b,LL c,LL &Ans) {max_a[x]=dis_[x]*a+c; max_b[x]=dis_[x]*b+c;for (LL p=last[x];p;p=pre[p]) {if (other[p]==fa) continue;dp(other[p],x,a,b,c,Ans);max_a[x]=max(max_a[x],max_a[other[p]]+c);max_b[x]=max(max_b[x],max_b[other[p]]+c);}LL aa=0,bb=0;//printf("%d %d\n",max_a[x],max_b[x]);for (LL p=last[x];p;p=pre[p]) {if (other[p]==fa) continue;Ans=max(Ans,max_a[x]+c+dis_[x]*b);Ans=max(Ans,max_b[x]+c+dis_[x]*a);}//printf("%d %d\n",x,Ans);for (LL p=last[x];p;p=pre[p]) {if (other[p]==fa) continue;if (max_a[other[p]]>max_a[aa]) aa=other[p];if (max_b[other[p]]>max_b[bb]) bb=other[p];}//printf("%d %d\n",x,Ans);for (LL p=last[x];p;p=pre[p]) {if (other[p]==fa) continue;if (other[p]!=aa) Ans=max(Ans,max_a[aa]+max_b[other[p]]+(c<<1));//printf("%d %d %d %d\n",Ans,max_a[aa],max_b[other[p]],c<<1);if (other[p]!=bb) Ans=max(Ans,max_b[bb]+max_a[other[p]]+(c<<1));}//printf("%d %d\n",aa,max_a[aa]);//printf("%d %d\n",x,Ans);
}LL work(LL le,LL x,LL ri) {LL a=size[le],b=size[ri],c=size[le]*size[ri],ans=0;LL cur[4]; cur[1]=cur[2]=cur[3]=0;for (LL i=1;i<=n;i++) cur[col[i]]=max(cur[col[i]],dis_[i]);//printf("fuck %d %d\n",col[le],col[ri]);ans=cur[col[le]]*size[x]+a*size[x]+cur[col[ri]]*size[x]+size[x]*b+a*cur[col[ri]]+b*cur[col[le]];//printf("fuck\n");memset(max_a,0,sizeof max_a);memset(max_b,0,sizeof max_b);LL Ans=-1;dp(x,-1,a,b,c,Ans);Ans=max(Ans,c<<1);//printf("%d %d\n",ans,Ans);ans+=Ans;//printf("%d\n",ans);return ans;
}void Work(LL x,LL fa) {for (LL p=last[x];p;p=pre[p]) {if (other[p]==fa) continue;Work(other[p],x);}//printf("%d %d %d\n",x,a[x],cnt[x]);if (a[x]^cnt[x]) {for (LL p=last[x];p;p=pre[p]) if (other[p]==fa) flag[num[p]]=1;cnt[fa]^=1;};
}int main() {freopen("lct.in","r",stdin); freopen("lct.out","w",stdout);scanf("%lld%lld\n",&n,&m);char c;for (LL i=1;i<=n;i++) scanf("%c",&c),a[i]=(c=='B')?1:0;for (LL i=1;i<=m;i++) {LL x,y;scanf("%lld%lld",&x,&y);connect(x,y,i); connect(y,x,i);}LL sum=0;for (LL i=1;i<=n;i++) if (!col[i]) paint(i,-1,++sum),rot[sum]=i;for (LL i=1;i<=3;i++) if (rot[i]) make_dis(rot[i],-1),make_dis_(rot[i],-1,size[rot[i]]);for (LL i=1;i<=3;i++) if (rot[i]) calc(rot[i],-1,size[rot[i]]);//for (LL i=1;i<=n;i++) printf("%d ",col[i]); printf("\n");//printf("%d %d %d\n",rot[1],rot[2],rot[3]);//for (LL i=1;i<=n;i++) printf("%d %d %d %d\n",i,dis[i],dis_[i],size[i]);//for (LL i=1;i<=3;i++) printf("%d ",ANS[i]); printf("\n");if (sum==2) {LL cur[3];cur[1]=cur[2]=0;for (LL i=1;i<=n;i++) cur[col[i]]=max(cur[col[i]],dis_[i]);LL Ans=ANS[1]+ANS[2]+cur[1]*size[rot[2]]+cur[2]*size[rot[1]]+size[rot[1]]*size[rot[2]];printf("%lld\n",Ans);//printf("%d %d\n",cur[1],cur[2]);//printf("%d %d\n",size[rot[1]],size[rot[2]]);//printf("%d %d\n",ANS[1],ANS[2]);} else {LL Ans=0;Ans=max(Ans,work(rot[2],rot[1],rot[3]));Ans=max(Ans,work(rot[1],rot[2],rot[3]));Ans=max(Ans,work(rot[1],rot[3],rot[2]));//printf("%d\n",Ans);Ans+=ANS[1]+ANS[2]+ANS[3];printf("%lld\n",Ans);}for (LL i=1;i<=n;i++) for (LL p=last[i];p;p=pre[p]) cnt[other[p]]++,cnt[i]++;//for (LL i=1;i<=n;i++) printf("%d\n",cnt[i]);//for (LL i=1;i<=n;i++) printf("%d\n",a[i]);for (LL i=1;i<=n;i++) cnt[i]/=2,cnt[i]%=2;for (LL i=1;i<=3;i++) Work(rot[i],-1);LL ans_=0;for (LL i=1;i<=m;i++) if (!flag[i]) ans_++;printf("%lld\n",ans_);for (LL i=1;i<=m;i++) if (!flag[i]) printf("%lld ",i); printf("\n");fclose(stdin); fclose(stdout);return 0;
}

 

 

 

转载于:https://www.cnblogs.com/BLADEVIL/p/3625012.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/461511.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

c++远征之模板篇——静态数据成员,静态成员函数

以下内容源于慕课网的学习整理&#xff0c;如有侵权&#xff0c;请告知删除。 1、静态数据成员 &#xff08;1&#xff09;不同于普通的数据成员&#xff0c;静态数据成员在没有实例化时&#xff0c;它也是存在的&#xff08;即它是和类共存的&#xff09;&#xff1b; &…

shell脚本自动备份MySQL数据库

脚本如下&#xff1a; #!/bin/bash #数据库IP dbserver127.0.0.1 #数据库用户名 dbuserroot #数据密码 dbpasswd123456 #数据库,如有多个库用空格分开 dbnamebrdb_jtkg_0222 brdb_jtkg_0425 #备份时间 backtimedate %Y%m%d-%H-%M #备份输出日志路径 logpath/home/mysqlbackup/e…

摈弃 Windows 低效率的工作方式,发掘 Linux 身上的 UNIX 气质

[原文链接] 摈弃 Windows 低效率的工作方式&#xff0c;发掘 Linux 身上的 UNIX 气质 我已经半年没有使用 Windows 的方式工作了。Linux 高效的完成了我所有的工作。 GNU/Linux 不是每个人都想用的。如果你只需要处理一般的事务&#xff0c;打游戏&#xff0c;那么你也许不需要…

c++远征之模板篇——运算符重载

以下内容源于慕课网的学习整理&#xff0c;如有侵权&#xff0c;请告知删除。 一、运算符重载的概念 给原有的运算符赋予新的功能。比如下面的截图&#xff0c;本来加号并不具备坐标的相加的功能&#xff0c;但是通过运算符重载可以实现该功能。 二、运算符重载的本质 本质是…

glClearDepth

opengl里面的深度缓存 在现实生活中&#xff0c;一个实心物体挡在另外一个实心物体的前面&#xff0c; 后面的那个物体有部分会被遮盖掉 那么opengl里面如何模拟这个情况呢&#xff1f; 每个物体的每个像素都有一个深度缓存的值&#xff08;在0到1之间&#xff0c;可以想象成是…

frp对http协议应用

前言 frp是一个开源的项目, 可用于内网穿透的高性能的反向代理应用&#xff0c;支持 tcp, udp 协议&#xff0c;为 http 和 https 应用协议提供了额外的能力&#xff0c;且尝试性支持了点对点穿透。 github地址&#xff1a;https://github.com/fatedier/frp 此处对http的应用做…

树形列(无限级联下拉列的曲线版本)

先上效果图&#xff1a; 1、列表 - 列表设置 - 创建栏&#xff0c;“类型”选择“托管元数据”&#xff0c;如下图&#xff1a; 2、选中“托管元数据”后&#xff0c;可以到下面编辑需要的树形啦&#xff1a; 3、编辑好&#xff0c;确定&#xff0c;搞定&#xff1b;可以到列表…

c++远征之模板篇——函数模板、类模板

以下内容源于慕课网的学习整理&#xff0c;如有侵权&#xff0c;请告知删除。 函数模板&#xff08;vs模板函数&#xff09; 1、为什么需要模板&#xff1f; 函数体相同&#xff0c;只是类型不一样而已。那么能否把数据的类型当做参数传递呢&#xff1f;肯定是可以的&#xff0…

国外知名的开源项目托管网站

国外知名的开源项目托管网站 托管站点Top20如下&#xff1a; 1. SourceForge SF为大家所熟知&#xff0c;开源项目的大本营&#xff0c;SF托管至少28万个开源项目&#xff0c;一天的下载量超过200万。 2. GitHub GitHub托管使用Git版本控制系统的公开和私有项目。 目前该网站托…

js初学总结

基础 交换变量方式 //利用第三方变量进行交换var num1 10;var num2 20;var temp;temp num1;num1 num2;num2 temp;console.log(num1);console.log(num2);//一般适用于数字交换var num1 10;var num2 20;num1 num1 num2;num2 num1 - num2;num1 num1 - num2;console.l…

js去空格函数(方法)

<script type"text/javascript"> //去左空格; function ltrim(s){ return s.replace(/(^\s*)/, ""); } //去右空格; function rtrim(s){ return s.replace(/(\s*$)/, ""); } //去左右空格; function trim…

c++远征之模板篇——标准模板库(STL)

以下内容源于慕课网的学习整理&#xff0c;如有侵权&#xff0c;请告知删除。 常见的设计模板 1、vector&#xff0c;向量 &#xff08;1&#xff09;本质是对数组的封装&#xff1b; &#xff08;2&#xff09;能够在常数时间内完成读取&#xff1b; &#xff08;3&#xf…

避免Castle Windsor引起的内存泄露

原文地址&#xff1a; http://nexussharp.wordpress.com/2012/04/21/castle-windsor-avoid-memory-leaks-by-learning-the-underlying-mechanics/CASTLE WINDSOR: AVOID MEMORY LEAKS BY LEARNING THE UNDERLYING MECHANICS Lifestyles In am not going to explain all the dif…

数据结构探险——队列篇

以下内容源于慕课网的学习整理&#xff0c;如有侵权&#xff0c;请告知删除。 1、什么是队列&#xff1f; &#xff08;1&#xff09;先入先出的模型&#xff08;FIFO&#xff09;。 &#xff08;2&#xff09;队头&#xff0c;队尾。 &#xff08;3&#xff09;细分为普通队…

Linux系统时间和硬件时间设置

在Linux中有硬件时钟与系统时钟两种时钟。硬件时钟是指主机板上的时钟设备&#xff0c;也就是通常可在BIOS画面设定的时钟。系统时钟则是指kernel中的时钟。所有Linux相关指令与函数都是读取系统时钟的设定。因为存在两种不同的时钟&#xff0c;那么它们之间就会存在差异。当Li…

小程序购物车抛物线(贝塞尔曲线实现)

话不多说上代码https://developers.weixin.qq.com/s/U4SmwPmg7uaj 转载于:https://www.cnblogs.com/gkxNB/p/11400075.html

hdu2570 迷瘴

题目链接&#xff1a;http://acm.hdu.edu.cn/showproblem.php?pid2570 题目的意思&#xff1a;给你n个体积相同浓度不同的解药&#xff0c;让你配置出浓度不大于w的最大体积的解药&#xff1a; 解题过程:就是一个简单的排序加判断。弄了很久还是没有弄好&#xff0c;后来才发现…

数据结构与算法之冒泡排序

转载于:https://www.cnblogs.com/yakun/p/3634457.html

数据结构探险——栈篇

以下内容源于慕课网的学习整理&#xff0c;如有侵权&#xff0c;请告知删除。 1、栈要素 栈底&#xff08;不变&#xff09;、栈顶&#xff08;随着入栈和出栈而改变&#xff09; 2、栈机制的实现 &#xff08;1&#xff09;栈的相关机制 判断栈的空满&#xff1b;入栈、出栈…

windows下修改tomcat的startup.bat脚本文件后台运行

1、修改startup.bat文件 rem Get remaining unshifted command line arguments and save them in the set CMD_LINE_ARGS :setArgs if ""%1"""""" goto doneSetArgs set CMD_LINE_ARGS%CMD_LINE_ARGS% %1 shift goto setArgs :doneSet…