首先,对于从每个点出发的路径,答案一定是过这个点的路径所覆盖的点数。然后可以做树上差分,对每个点记录路径产生总贡献,然后做一个树剖维护,对每个点维护一个动态开点线段树。最后再从根节点开始做一遍dfs,把每个节点对应的线段树启发式合并即可。时空复杂度均为O(nlog2n)。听说还有一个log的做法,但感觉太神仙不会,不过2个log能过就不管了。

#include<bits/stdc++.h>
#define lson l,mid,tr[rt].lc
#define rson mid+1,r,tr[rt].rc
using namespace std;
const int N=1e5+;
struct Seg{int lc,rc,tag,sz;}tr[N*];
int n,m,cnt,fa[N],sz[N],dep[N],son[N],top[N],dfn[N],rt[N];
long long ans;
vector<int>G[N];
void dfs1(int u,int f)
{
sz[u]=,dep[u]=dep[f]+,fa[u]=f;
for(int i=;i<G[u].size();i++)
if(G[u][i]!=f)
{
dfs1(G[u][i],u),sz[u]+=sz[G[u][i]];
if(sz[son[u]]<sz[G[u][i]])son[u]=G[u][i];
}
}
void dfs2(int u,int tp)
{
top[u]=tp,dfn[u]=++cnt;
if(son[u])dfs2(son[u],tp);
for(int i=;i<G[u].size();i++)if(G[u][i]!=fa[u]&&G[u][i]!=son[u])dfs2(G[u][i],G[u][i]);
}
void pushup(int rt,int len)
{if(tr[rt].tag)tr[rt].sz=len;else tr[rt].sz=tr[tr[rt].lc].sz+tr[tr[rt].rc].sz;}
void modify(int rt,int v,int len){tr[rt].tag+=v;pushup(rt,len);}
void update(int L,int R,int v,int l,int r,int&rt)
{
if(!rt)rt=++cnt;
if(L<=l&&r<=R){modify(rt,v,r-l+);return;}
int mid=l+r>>;
if(L<=mid)update(L,R,v,lson);
if(R>mid)update(L,R,v,rson);
pushup(rt,r-l+);
}
void Update(int&rt,int x,int y,int v)
{
while(top[x]!=top[y])update(dfn[top[x]],dfn[x],v,,n,rt),x=fa[top[x]];
if(x!=y)update(dfn[y]+,dfn[x],v,,n,rt);
}
int lca(int x,int y)
{
while(top[x]!=top[y])if(dep[top[x]]<dep[top[y]])y=fa[top[y]];else x=fa[top[x]];
return dep[x]<dep[y]?x:y;
}
int merge(int u,int v,int l,int r)
{
if(!u||!v)return u+v;
tr[u].tag+=tr[v].tag;
if(l==r){pushup(u,);return u;}
int mid=l+r>>;
tr[u].lc=merge(tr[u].lc,tr[v].lc,l,mid);
tr[u].rc=merge(tr[u].rc,tr[v].rc,mid+,r);
pushup(u,r-l+);
return u;
}
void dfs3(int u,int f)
{
for(int i=;i<G[u].size();i++)
if(G[u][i]!=f)dfs3(G[u][i],u),rt[u]=merge(rt[u],rt[G[u][i]],,n);
ans+=max(tr[rt[u]].sz-,);
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=,x,y;i<n;i++)scanf("%d%d",&x,&y),G[x].push_back(y),G[y].push_back(x);
dfs1(,);
dfs2(,);
cnt=;
for(int i=,x,y,f;i<=m;i++)
{
scanf("%d%d",&x,&y);
f=lca(x,y);
Update(rt[x],x,fa[f],),Update(rt[x],y,f,);
Update(rt[y],x,fa[f],),Update(rt[y],y,f,);
Update(rt[f],x,fa[f],-),Update(rt[f],y,f,-);
if(fa[f])Update(rt[fa[f]],x,fa[f],-),Update(rt[fa[f]],y,f,-);
}
dfs3(,);
cout<<ans/;
}

[ZJOI2019]语言(树链剖分+动态开点线段树+启发式合并)的更多相关文章

  1. 【bzoj4999】This Problem Is Too Simple! 树链剖分+动态开点线段树

    题目描述 给您一颗树,每个节点有个初始值. 现在支持以下两种操作: 1. C i x(0<=x<2^31) 表示将i节点的值改为x. 2. Q i j x(0<=x<2^31) ...

  2. [bzoj 3531][SDOI2014]旅行(树链剖分+动态开点线段树)

    题目:http://www.lydsy.com:808/JudgeOnline/problem.php?id=3531 分析: 对于每个颜色(颜色<=10^5)都建立一颗线段树 什么!那么不是M ...

  3. 洛谷P3313 [SDOI2014]旅行(树链剖分 动态开节点线段树)

    题意 题目链接 Sol 树链剖分板子 + 动态开节点线段树板子 #include<bits/stdc++.h> #define Pair pair<int, int> #def ...

  4. BZOJ 3531 [Sdoi2014]旅行 树链剖分+动态开点线段树

    题意 S国有N个城市,编号从1到N.城市间用N-1条双向道路连接,满足从一个城市出发可以到达其它所有城市.每个城市信仰不同的宗教,如飞天面条神教.隐形独角兽教.绝地教都是常见的信仰. 为了方便,我们用 ...

  5. bzoj3531: [Sdoi2014]旅行 (树链剖分 && 动态开点线段树)

    感觉动态开点线段树空间复杂度好优秀呀 树剖裸题 把每个宗教都开一颗线段树就可以了 但是我一直TLE 然后调了一个小时 为什么呢 因为我 #define max(x, y) (x > y ? x ...

  6. 【BZOJ3531】[Sdoi2014]旅行 树链剖分+动态开点线段树

    [BZOJ3531][Sdoi2014]旅行 Description S国有N个城市,编号从1到N.城市间用N-1条双向道路连接,满足从一个城市出发可以到达其它所有城市.每个城市信仰不同的宗教,如飞天 ...

  7. BZOJ4999: This Problem Is Too Simple!树链剖分+动态开点线段树

    题目大意:将某个节点的颜色变为x,查询i,j路径上多少个颜色为x的点... 其实最开始一看就是主席树+树状数组+DFS序...但是过不去...MLE+TLE BY FCWWW 其实树剖裸的一批...只 ...

  8. bzoj3531——树链剖分+动态开点线段树

    3531: [Sdoi2014]旅行 Time Limit: 20 Sec  Memory Limit: 512 MB Description S国有N个城市,编号从1到N.城市间用N-1条双向道路连 ...

  9. [LuoguU41039]PION后缀自动机 树链剖分+动态开点线段树

    链接 刚开始看出题人题解都吓蒙掉了,还以为是什么难题,结果就一板子题 思路:对每一个文件名开一棵线段树,然后树剖即可 #include<bits/stdc++.h> #define REP ...

随机推荐

  1. eclipse导入maven工程,右键没有build path和工程不能自动编译解决方法

    原文链接:https://blog.csdn.net/wusunshine/article/details/52506389 eclipse导入maven工程,右键没有build path解决方法: ...

  2. Javascript里EQ、NE、GT、LT、GE、LE含义

    EQ 就是 EQUAL等于 NE就是 NOT EQUAL不等于 GT 就是 GREATER THAN大于  LT 就是 LESS THAN小于 GE 就是 GREATER THAN OR EQUAL ...

  3. Innodb特性以及实现原理

    Innodb五大特性 1.insert buffer2.double write3.自适应哈希索引4.异步io5.邻接页刷新 1.insert buffer(change buffer) 作用:将非聚 ...

  4. java基础——深拷贝和浅拷贝的区别

    浅拷贝:对基本数据类型进行值传递,对引用数据类型进行引用传递般的拷贝,此为浅拷贝. 深拷贝:对基本数据类型进行值传递,对引用数据类型船舰一个新的对象,并复制内容,这是深拷贝.

  5. [BJDCTF2020]Mark loves cat

    0x00 知识点 GitHack读取源码 $$会导致变量覆盖漏洞 0x01解题 dirsearch扫描一下,发现/.git目录,用githack获取一下源码. <?php include 'fl ...

  6. Hibernate(一)——入门

    1. 前言         Hibernate是一个开放源代码的ORM持久化框架,它对JDBC进行了非常轻量级的对象封装,使得Java程序员可以随心所欲的使用对象编程思维来操纵数据库.         ...

  7. C++逐词读取txt

    这一篇来写下std::ifstream读取txt的另一种方式,逐词读取,上一篇是按行读取,逐词读取的话每个单词都以空格或者换行等符号间隔开. 代码如下: #include "stdafx.h ...

  8. 阿里云-容器服务之集群服务 k8s(Jenkins+gitlab+k8s的devops)- 04

    配置jenkins和gitlab: 1.进入jenkins,新增一个项目,demo-piepeline,创建好,点击配置, 2 .设置镜像地址的命名空间: 3.设置镜像的名字 4.设置代码的分支或者t ...

  9. 201712-2 游戏 Java

    思路: 第一感觉有点像约瑟夫环.想到用队列解决比较好理解 import java.util.LinkedList; import java.util.Queue; import java.util.S ...

  10. selenium破解人人登陆验证码

    from selenium import webdriverfrom PIL import Imagefrom chaojiying import Chaojiying_Clientimport ti ...