传送门

Description

给定一棵\(n\)个点的树和\(m\)条链,两个点可以联会当且仅当它们同在某一条链上,求可以联会的点的方案数

\(n,m\leq10^5\)

Solution 

考虑计算每个点的贡献,然后将贡献和除以\(2\)

相当于求出对于每个点经过它的所有链端点的虚树的大小(显然这些链的并就是一个

每个虚树都先加上了根节点,可以保证以下求虚树大小的做法合法:

注意:这里的根节点是\(1\)号节点,但是我们并不看作\(1\)号节点一定在这个虚树内——它更像是一个等价于\(1\)号点的虚拟节点

先对所有端点按照\(dfs\)序进行排序,这样根肯定在第一个

然后在按顺序加入每个点的过程中

加上这个点连向当前虚树最短链的长度,也就是\(dep_{a[i]}-dep_{lca(a[i],a[i-1])}\)

\(last\)指的是上一个加入的点

对于最小的那个节点,它的贡献就是\(dep[a[1]]\)

我们考虑线段树的分治的过程,假设我们先分别求出了\(dfs\)序在\([l,mid]\)和\([mid+1,r]\)中端点的虚树信息

接下来要将其合并,这时,其实只需要合并左区间中最大的和右区间中最小的即可,这时我们是不算根节点的

合并之后,发现多算了一些点,具体来说,是重复计算了从根到\(LCA\)的一段路径,将其减去

最后,求得虚树大小后,还要减去从根到\(LCA\)的长度,在合并的同时维护一下集合的\(lca\)即可

在本题中,求\(lca\)采用\(RMQ\)方法

树上差分,在端点和端点的\(lca\)的父亲处进行加点和删点操作

相当于对线段树进行单点修改

从孩子那里继承信息需要用到线段树合并

复杂度是\(O(n\log n)\)

Code 

  1. #include<bits/stdc++.h>
  2. #define ll long long
  3. using namespace std;
  4. #define reg register
  5. inline int read()
  6. {
  7. int x=0,f=1;char ch=getchar();
  8. while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
  9. while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
  10. return x*f;
  11. }
  12. const int MN=1e5+5,MM=4e6+5;
  13. int n,m;ll ans;
  14. struct ed{int to,nex;}e[MN<<1];int hr[MN],en;
  15. inline void ins(int x,int y)
  16. {
  17. e[++en]=(ed){y,hr[x]};hr[x]=en;
  18. e[++en]=(ed){x,hr[y]};hr[y]=en;
  19. }
  20. /*------------求lca------------*/
  21. int st[MN<<1][20],eu[MN],id[MN],dfn[MN],pin,dep[MN],fa[MN],dind,lg[MN<<1];
  22. void dfs(int x,int f)
  23. {
  24. id[dfn[x]=++pin]=x;st[dind][0]=x;
  25. eu[x]=++dind;dep[x]=dep[fa[x]=f]+1;
  26. for(int i=hr[x];i;i=e[i].nex)if(e[i].to^f)
  27. st[dind][0]=x,++dind,dfs(e[i].to,x);
  28. }
  29. inline void init()
  30. {
  31. dfs(1,0);register int i,j;
  32. for(i=2;i<=dind;++i)lg[i]=lg[i>>1]+1;
  33. for(j=1;j<20;++j)for(i=1;i<=dind;++i)
  34. {
  35. if(i+(1<<j)>dind) break;
  36. st[i][j]=dep[st[i][j-1]]<dep[st[i+(1<<j-1)][j-1]]?st[i][j-1]:st[i+(1<<j-1)][j-1];
  37. }
  38. }
  39. int LCA(int x,int y)
  40. {
  41. if(!x||!y) return x|y;
  42. if(x==y) return x;
  43. x=eu[x];y=eu[y];if(x>y)swap(x,y);
  44. int b=lg[y-x];
  45. if(dep[st[x][b]]<dep[st[y-(1<<b)][b]])
  46. return st[x][b];
  47. return st[y-(1<<b)][b];
  48. }
  49. /*------------线段树合并------------*/
  50. struct xxx{
  51. int x,y,z;
  52. xxx(int x,int y,int z):x(x),y(y),z(z){}
  53. };
  54. std::vector<xxx> opt[MN];
  55. int ml[MM],mr[MM],ls[MM],rs[MM],v[MM],sum[MM],lca[MM],rt[MN],tot;
  56. void up(int x)
  57. {
  58. ml[x]=ml[ls[x]]?ml[ls[x]]:ml[rs[x]];
  59. mr[x]=mr[rs[x]]?mr[rs[x]]:mr[ls[x]];
  60. v[x]=v[ls[x]]+v[rs[x]];
  61. if(!v[ls[x]]||!v[rs[x]]) sum[x]=sum[ls[x]]+sum[rs[x]];
  62. else sum[x]=sum[ls[x]]+sum[rs[x]]-dep[LCA(id[mr[ls[x]]],id[ml[rs[x]]])];
  63. if(lca[ls[x]]&&lca[rs[x]]) lca[x]=LCA(lca[ls[x]],lca[rs[x]]);
  64. else lca[x]=lca[ls[x]]|lca[rs[x]];
  65. }
  66. int Merge(int x,int y,int l,int r)
  67. {
  68. if(!x||!y) return x|y;
  69. if(l==r)
  70. {
  71. v[x]+=v[y];
  72. if(v[x]) ml[x]=mr[x]=l,lca[x]=id[l],sum[x]=dep[id[l]];
  73. else ml[x]=mr[x]=lca[x]=sum[x]=0;
  74. return x;
  75. }
  76. int mid=(l+r)>>1;
  77. ls[x]=Merge(ls[x],ls[y],l,mid);
  78. rs[x]=Merge(rs[x],rs[y],mid+1,r);
  79. up(x);return x;
  80. }
  81. void Modify(int &x,int l,int r,int a,int b)
  82. {
  83. if(!x) x=++tot;
  84. if(l==r)
  85. {
  86. v[x]+=b;
  87. if(v[x]) ml[x]=mr[x]=l,lca[x]=id[l],sum[x]=dep[id[l]];
  88. else ml[x]=mr[x]=lca[x]=sum[x]=0;
  89. return;
  90. }
  91. int mid=(l+r)>>1;
  92. if(a<=mid) Modify(ls[x],l,mid,a,b);
  93. else Modify(rs[x],mid+1,r,a,b);
  94. up(x);
  95. }
  96. void Solve(int x)
  97. {
  98. register int i;
  99. for(i=hr[x];i;i=e[i].nex)if(e[i].to^fa[x])
  100. Solve(e[i].to),rt[x]=Merge(rt[x],rt[e[i].to],1,n);
  101. for(i=opt[x].size()-1;~i;--i)
  102. Modify(rt[x],1,n,opt[x][i].x,opt[x][i].z),
  103. Modify(rt[x],1,n,opt[x][i].y,opt[x][i].z);
  104. ans+=sum[rt[x]]-dep[lca[rt[x]]];
  105. }
  106. int main()
  107. {
  108. n=read();m=read();
  109. register int i,x,y,z;
  110. for(i=1;i<n;++i) x=read(),ins(x,read());
  111. init();
  112. for(i=1;i<=m;++i)
  113. {
  114. x=read(),y=read();z=LCA(x,y);
  115. opt[x].push_back(xxx(dfn[x],dfn[y],1));
  116. opt[y].push_back(xxx(dfn[x],dfn[y],1));
  117. opt[z].push_back(xxx(dfn[x],dfn[y],-1));
  118. opt[fa[z]].push_back(xxx(dfn[x],dfn[y],-1));
  119. }
  120. ans=0;Solve(1);
  121. return 0*printf("%lld\n",ans>>1);
  122. }

Blog来自PaperCloud,未经允许,请勿转载,TKS!

「ZJOI2019」语言的更多相关文章

  1. 【LOJ】#3046. 「ZJOI2019」语言

    LOJ#3046. 「ZJOI2019」语言 先orz zsy吧 有一个\(n\log^3n\)的做法是把树链剖分后,形成logn个区间,这些区间两两搭配可以获得一个矩形,求矩形面积并 然后就是对于一 ...

  2. 「ZJOI2019」语言 解题报告

    「ZJOI2019」语言 3个\(\log\)做法比较简单,但是写起来还是有点麻烦的. 大概就是树剖把链划分为\(\log\)段,然后任意两段可以组成一个矩形,就是个矩形面积并,听说卡卡就过去了. 好 ...

  3. @loj - 3046@「ZJOI2019」语言

    目录 @description@ @solution@ @accepted code@ @details@ @description@ 九条可怜是一个喜欢规律的女孩子.按照规律,第二题应该是一道和数据 ...

  4. 【线段树 树链剖分 差分 经典技巧】loj#3046. 「ZJOI2019」语言【未完】

    还是来致敬一下那过往吧 题目分析 先丢代码 #include<bits/stdc++.h> ; ; ; struct node { int top,son,fa,tot; }a[maxn] ...

  5. bzoj5518 & loj3046 「ZJOI2019」语言 线段树合并+树链的并

    题目传送门 https://loj.ac/problem/3046 题解 首先问题就是问有多少条路径是给定的几条路径中的一条的一个子段. 先考虑链的做法. 枚举右端点 \(i\),那么求出 \(j\) ...

  6. 「ZJOI2019」&「十二省联考 2019」题解索引

    「ZJOI2019」&「十二省联考 2019」题解索引 「ZJOI2019」 「ZJOI2019」线段树 「ZJOI2019」Minimax 搜索 「十二省联考 2019」 「十二省联考 20 ...

  7. LOJ3044. 「ZJOI2019」Minimax 搜索

    LOJ3044. 「ZJOI2019」Minimax 搜索 https://loj.ac/problem/3044 分析: 假设\(w(1)=W\),那么使得这个值变化只会有两三种可能,比\(W\)小 ...

  8. Loj #3044. 「ZJOI2019」Minimax 搜索

    Loj #3044. 「ZJOI2019」Minimax 搜索 题目描述 九条可怜是一个喜欢玩游戏的女孩子.为了增强自己的游戏水平,她想要用理论的武器武装自己.这道题和著名的 Minimax 搜索有关 ...

  9. Loj #3045. 「ZJOI2019」开关

    Loj #3045. 「ZJOI2019」开关 题目描述 九条可怜是一个贪玩的女孩子. 这天,她和她的好朋友法海哥哥去玩密室逃脱.在他们面前的是 \(n\) 个开关,开始每个开关都是关闭的状态.要通过 ...

随机推荐

  1. Gson含抽象类的反序列化

    Gson含抽象类的反序列化 场景描述: 反序列化A类的时候,这个类里面有一个抽象类属性B,B的实现类C里面又有一个抽象类属性D,D的实现类是E 实体类准备 public class A impleme ...

  2. 【开发工具】- Idea.2018.02注册码激活

    1.从下面地址下载一个jar包,名称是  JetbrainsCrack-3.1-release-enc.jar 下载地址: 链接: https://pan.baidu.com/s/1VZjklI3qh ...

  3. CI隐藏入口文件index.php

    1.需要apache打开rewrite_module,然后修改httpd.conf的AllowOverride none 为AllowOverride All(里面,不同的环境目录不同) 2.在CI的 ...

  4. 供应链管理如何提高效率?APS系统成优化引擎

    APS系统,虽然它的起兴只有短短的十几年,但是在这段时间里面,它为很多企业解决了很多人工手动.脑力不可解决的问题. 所以APS被誉为供应链优化引擎,APS常常被称为高级计划与排程,但也有称为高级计划系 ...

  5. nrm 工具的使用

    一.什么是nrm? 这是官方的原话: 开发的npm registry 管理工具 nrm, 能够查看和切换当前使用的registry, 最近NPM经常 down 掉, 这个还是很有用的哈哈 顾名思义,就 ...

  6. Linux“七大蠢”收录

    这个系列的文章,前段时间在微信公共平台(阿里技术嘉年华)上看过,写得很好. Linux"七大蠢"之一:万般皆文本 Linux"七大蠢"之二:处处有脚本 Linu ...

  7. PHP java时间戳转php时间戳

    /** * java时间戳转php时间戳 * @param int $javaUt java的时间戳 * @return int * @Date 2019/8/26 */ public static ...

  8. Yii2通过curl调用json-rpc接口

    Yii2可以通过json-rpc为前端提供接口数据,通常情况睛会使用异步的形式调用接口,有时也会使用curl调用接口数据. 一.异步调用json-rpc接口 $.ajax({ type: 'POST' ...

  9. gRPC应用C++

    1.  gRPC简述 RPC,远程方法调用,就是像调用本地方法一样调用远程方法. gRPC是Google实现的一种RPC框架,基于HTTP/2标准设计,带来诸如双向流.流控.头部压缩.单 TCP 连接 ...

  10. CentOS7源码安装Redis5.0.4非关系型数据库

    源码安装redis-5.0.4 一. 下载redis 1. 需要连接网络 二. 案例(另一种安装方法) [root@localhost ~]# wget http://download.redis.i ...