【题目描述】给定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点其中一点是另一点的祖先,还有开始觉得如果中间的树选择两个点肯定不能是同一点,所以边界就处理的不是特别好,但是可能会有某些点单独构成树,这样的话就必须连接同一个点。第二问还是比较容易写的。

  1. //By BLADEVIL
  2. #include <cstdio>
  3. #include <cstring>
  4. #include <algorithm>
  5. #define maxn 100010
  6. #define LL long long
  7.  
  8. using namespace std;
  9.  
  10. LL n,m,l;
  11. LL a[maxn],pre[maxn<<],other[maxn<<],last[maxn],col[maxn],rot[],num[maxn<<],flag[maxn];
  12. LL dis_[maxn],dis[maxn],size[maxn],ans[maxn],ANS[],max_a[maxn],max_b[maxn],cnt[maxn];
  13.  
  14. void connect(LL x,LL y,LL z) {
  15. pre[++l]=last[x];
  16. last[x]=l;
  17. other[l]=y;
  18. num[l]=z;
  19. }
  20.  
  21. void paint(LL x,LL fa,LL c) {
  22. col[x]=c;
  23. for (LL p=last[x];p;p=pre[p]) {
  24. if (other[p]==fa) continue;
  25. paint(other[p],x,c);
  26. }
  27. }
  28.  
  29. void make_dis(LL x,LL fa) {
  30. dis[x]=; size[x]=;
  31. for (LL p=last[x];p;p=pre[p]) {
  32. if (other[p]==fa) continue;
  33. make_dis(other[p],x);
  34. dis[x]+=dis[other[p]]+size[other[p]];
  35. size[x]+=size[other[p]];
  36. }
  37. }
  38.  
  39. void make_dis_(LL x,LL fa,LL s) {
  40. if (fa!=-) dis_[x]=dis_[fa]-size[x]-dis[x]+s-size[x]+dis[x]; else dis_[x]=dis[x];
  41. for (LL p=last[x];p;p=pre[p]) {
  42. if (other[p]==fa) continue;
  43. make_dis_(other[p],x,s);
  44. }
  45. }
  46.  
  47. void calc(LL x,LL fa,LL s) {
  48. for (LL p=last[x];p;p=pre[p]) {
  49. if (other[p]==fa) continue;
  50. ANS[col[x]]+=size[other[p]]*(s-size[other[p]]);
  51. calc(other[p],x,s);
  52. }
  53. }
  54.  
  55. void dp(LL x,LL fa,LL a,LL b,LL c,LL &Ans) {
  56. max_a[x]=dis_[x]*a+c; max_b[x]=dis_[x]*b+c;
  57. for (LL p=last[x];p;p=pre[p]) {
  58. if (other[p]==fa) continue;
  59. dp(other[p],x,a,b,c,Ans);
  60. max_a[x]=max(max_a[x],max_a[other[p]]+c);
  61. max_b[x]=max(max_b[x],max_b[other[p]]+c);
  62. }
  63. LL aa=,bb=;
  64. //printf("%d %d\n",max_a[x],max_b[x]);
  65. for (LL p=last[x];p;p=pre[p]) {
  66. if (other[p]==fa) continue;
  67. Ans=max(Ans,max_a[x]+c+dis_[x]*b);
  68. Ans=max(Ans,max_b[x]+c+dis_[x]*a);
  69. }
  70. //printf("%d %d\n",x,Ans);
  71. for (LL p=last[x];p;p=pre[p]) {
  72. if (other[p]==fa) continue;
  73. if (max_a[other[p]]>max_a[aa]) aa=other[p];
  74. if (max_b[other[p]]>max_b[bb]) bb=other[p];
  75. }
  76. //printf("%d %d\n",x,Ans);
  77. for (LL p=last[x];p;p=pre[p]) {
  78. if (other[p]==fa) continue;
  79. if (other[p]!=aa) Ans=max(Ans,max_a[aa]+max_b[other[p]]+(c<<));
  80. //printf("%d %d %d %d\n",Ans,max_a[aa],max_b[other[p]],c<<1);
  81. if (other[p]!=bb) Ans=max(Ans,max_b[bb]+max_a[other[p]]+(c<<));
  82. }
  83. //printf("%d %d\n",aa,max_a[aa]);
  84. //printf("%d %d\n",x,Ans);
  85. }
  86.  
  87. LL work(LL le,LL x,LL ri) {
  88. LL a=size[le],b=size[ri],c=size[le]*size[ri],ans=;
  89. LL cur[]; cur[]=cur[]=cur[]=;
  90. for (LL i=;i<=n;i++) cur[col[i]]=max(cur[col[i]],dis_[i]);
  91. //printf("fuck %d %d\n",col[le],col[ri]);
  92. 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]];
  93. //printf("fuck\n");
  94. memset(max_a,,sizeof max_a);
  95. memset(max_b,,sizeof max_b);
  96. LL Ans=-;
  97. dp(x,-,a,b,c,Ans);
  98. Ans=max(Ans,c<<);
  99. //printf("%d %d\n",ans,Ans);
  100. ans+=Ans;
  101. //printf("%d\n",ans);
  102. return ans;
  103. }
  104.  
  105. void Work(LL x,LL fa) {
  106. for (LL p=last[x];p;p=pre[p]) {
  107. if (other[p]==fa) continue;
  108. Work(other[p],x);
  109. }
  110. //printf("%d %d %d\n",x,a[x],cnt[x]);
  111. if (a[x]^cnt[x]) {
  112. for (LL p=last[x];p;p=pre[p])
  113. if (other[p]==fa) flag[num[p]]=;
  114. cnt[fa]^=;
  115. };
  116. }
  117.  
  118. int main() {
  119. freopen("lct.in","r",stdin); freopen("lct.out","w",stdout);
  120. scanf("%lld%lld\n",&n,&m);
  121. char c;
  122. for (LL i=;i<=n;i++) scanf("%c",&c),a[i]=(c=='B')?:;
  123. for (LL i=;i<=m;i++) {
  124. LL x,y;
  125. scanf("%lld%lld",&x,&y);
  126. connect(x,y,i); connect(y,x,i);
  127. }
  128. LL sum=;
  129. for (LL i=;i<=n;i++) if (!col[i]) paint(i,-,++sum),rot[sum]=i;
  130. for (LL i=;i<=;i++) if (rot[i]) make_dis(rot[i],-),make_dis_(rot[i],-,size[rot[i]]);
  131. for (LL i=;i<=;i++) if (rot[i]) calc(rot[i],-,size[rot[i]]);
  132. //for (LL i=1;i<=n;i++) printf("%d ",col[i]); printf("\n");
  133. //printf("%d %d %d\n",rot[1],rot[2],rot[3]);
  134. //for (LL i=1;i<=n;i++) printf("%d %d %d %d\n",i,dis[i],dis_[i],size[i]);
  135. //for (LL i=1;i<=3;i++) printf("%d ",ANS[i]); printf("\n");
  136. if (sum==) {
  137. LL cur[];
  138. cur[]=cur[]=;
  139. for (LL i=;i<=n;i++) cur[col[i]]=max(cur[col[i]],dis_[i]);
  140. LL Ans=ANS[]+ANS[]+cur[]*size[rot[]]+cur[]*size[rot[]]+size[rot[]]*size[rot[]];
  141. printf("%lld\n",Ans);
  142. //printf("%d %d\n",cur[1],cur[2]);
  143. //printf("%d %d\n",size[rot[1]],size[rot[2]]);
  144. //printf("%d %d\n",ANS[1],ANS[2]);
  145. } else {
  146. LL Ans=;
  147. Ans=max(Ans,work(rot[],rot[],rot[]));
  148. Ans=max(Ans,work(rot[],rot[],rot[]));
  149. Ans=max(Ans,work(rot[],rot[],rot[]));
  150. //printf("%d\n",Ans);
  151. Ans+=ANS[]+ANS[]+ANS[];
  152. printf("%lld\n",Ans);
  153. }
  154. for (LL i=;i<=n;i++)
  155. for (LL p=last[i];p;p=pre[p]) cnt[other[p]]++,cnt[i]++;
  156. //for (LL i=1;i<=n;i++) printf("%d\n",cnt[i]);
  157. //for (LL i=1;i<=n;i++) printf("%d\n",a[i]);
  158. for (LL i=;i<=n;i++) cnt[i]/=,cnt[i]%=;
  159. for (LL i=;i<=;i++) Work(rot[i],-);
  160. LL ans_=;
  161. for (LL i=;i<=m;i++) if (!flag[i]) ans_++;
  162. printf("%lld\n",ans_);
  163. for (LL i=;i<=m;i++) if (!flag[i]) printf("%lld ",i); printf("\n");
  164. fclose(stdin); fclose(stdout);
  165. return ;
  166. }

【HNOI】 lct tree-dp的更多相关文章

  1. 【BZOJ】2631: tree LCT

    [题意]给定n个点的树,每个点初始权值为1,m次操作:1.x到y的点加值,2.断一条边并连一条边,保证仍是树,3.x到y的点乘值,4.x到y的点权值和取模.n,m<=10^5. [算法]Link ...

  2. 【BZOJ2212】[Poi2011]Tree Rotations 线段树合并

    [BZOJ2212][Poi2011]Tree Rotations Description Byteasar the gardener is growing a rare tree called Ro ...

  3. 【题解】Digit Tree

    [题解]Digit Tree CodeForces - 716E 呵呵以为是数据结构题然后是淀粉质还行... 题目就是给你一颗有边权的树,问你有多少路径,把路径上的数字顺次写出来,是\(m\)的倍数. ...

  4. 【题解】POJ1934 Trip (DP+记录方案)

    [题解]POJ1934 Trip (DP+记录方案) 题意: 传送门 刚开始我是这么设状态的(谁叫我DP没学好) \(dp(i,j)\)表示钦定选择\(i\)和\(j\)的LCS,然而你会发现这样钦定 ...

  5. 【题解】[P4178 Tree]

    [题解]P4178 Tree 一道点分治模板好题 不知道是不是我见到的题目太少了,为什么这种题目都是暴力开值域的桶QAQ?? 问点对,考虑点分治吧.直接用值域树状数组开下来,统计的时候直接往树状数组里 ...

  6. 【HNOI】合唱队

    [HNOI]合唱队 题意 对于一个初始序列,保证两两不同,通过一些变换得到目标序列: 第一个值直接插入空的当前队列 对于从第二个值开始的每个值 如果原序列中 $ a[i] $,若 $ a[i]> ...

  7. 【题解】剪纸条(dp)

    [题解]剪纸条(dp) HRBUST - 1828 网上搜不到题解?那我就来写一篇吧哈哈哈 最优化问题先考虑\(dp\),设\(dp(i)\)表示将前\(i\)个字符(包括\(i\))分割成不相交的回 ...

  8. 【题解】地精部落(DP)

    [题解]地精部落(DP) 设\(f_i\)表示强制第一个是谷的合法方案数 转移枚举一个排列的最大值在哪里,就把序列分成了互不相干的两个部分,把其中\(i-1\choose j-1\)的数字分配给前面部 ...

  9. 【总结】Link-Cut Tree

    这是一篇关于LCT的总结 加删边的好朋友--Link Cut Tree Link-Cut Tree,LCT的全称 可以说是从树剖引出的问题 树剖可以解决静态的修改或查询树的链上信息:那如果图会不断改变 ...

随机推荐

  1. Visual Studio 数据库架构比较

      一.前言 开发的时候在测试服务器上和线网服务器上面都有我们的数据库,当我们在线网上面修改或者新增一些字段后,线网的数据库也需要更新,这个时候根据表的修改记录,然后在线网上面一个一个增加修改很浪费效 ...

  2. H3C SNMP配置解析

    华为交换机snmp配置 snmp-agent                                           /使能snmp服务/snmp-agent local-engineid ...

  3. delphi dbgrid 批量保存

    unit uzcdbadd; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Fo ...

  4. Ajax在jQuery中的应用(加载异步数据、请求服务器数据)

    加载异步数据 jQuery中的load()方法 load(url,[data],[callback]) url:被加载的页面地址 [data]:可选项表示发送到服务器的数据,其格式为 key/valu ...

  5. 【.Net】浅谈C#中的值类型和引用类型

    在C#中,值类型和引用类型是相当重要的两个概念,必须在设计类型的时候就决定类型实例的行为.如果在编写代码时不能理解引用类型和值类型的区别,那么将会给代码带来不必要的异常.很多人就是因为没有弄清楚这两个 ...

  6. 【bzoj1704】[Usaco2007 Mar]Face The Right Way 自动转身机 贪心

    题目描述 农夫约翰有N(1≤N≤5000)只牛站成一排,有一些很乖的牛朝前站着.但是有些不乖的牛却朝后站着.农夫约翰需要让所有的牛都朝前站着.幸运的是约翰最近买了一个自动转身机.这个神奇的机器能使K( ...

  7. 【bzoj1030】[JSOI2007]文本生成器 AC自动机+dp

    题目描述 JSOI交给队员ZYX一个任务,编制一个称之为“文本生成器”的电脑软件:该软件的使用者是一些低幼人群,他们现在使用的是GW文本生成器v6版.该软件可以随机生成一些文章―――总是生成一篇长度固 ...

  8. [luogu5048] [Ynoi2019模拟赛] Yuno loves sqrt technology III

    题目链接 洛谷. Solution 思路同[BZOJ2724] [Violet 6]蒲公英,只不过由于lxl过于毒瘤,我们有一些更巧妙的操作. 首先还是预处理\(f[l][r]\)表示\(l\sim ...

  9. 洛谷 P4555 [国家集训队]最长双回文串 解题报告

    P4555 [国家集训队]最长双回文串 题目描述 顺序和逆序读起来完全一样的串叫做回文串.比如acbca是回文串,而abc不是(abc的顺序为abc,逆序为cba,不相同). 输入长度为\(n\)的串 ...

  10. 修改tomcat编码格式 & tomcat发布WEB项目供外网访问

    1.修改tomcat默认编码格式: 修改tomcat下的conf/server.xml文件,找到如下代码:       <Connector port="8080" prot ...