总览:
动态开点线段树,像暴力的合并(然而不是
时间复杂度: O ( n l o g n ) O(nlogn) O(nlogn)
模板:
inline int merge(int x,int y,int l,int r){
if(!x||!y) return x|y;
if(l==r){
//将y合并到x
return x;
}
int mid=(l+r)>>1;
tr[x].ls=merge(tr[x].ls,tr[y].ls,l,mid);
tr[x].rs=merge(tr[x].rs,tr[y].rs,mid+1,r);
pushup(x);
return x;
}
如果需要可持久化,可以动态开点
T1 P4556 [Vani有约会]雨天的尾巴 /【模板】线段树合并
思路:
差分
在 x,y 处加,lca(x,y),f(lca(x,y)) 处减
从叶子结点开始合并查询
代码:
#include <bits/stdc++.h>
using namespace std;
#define re register
namespace IO {
#define in Read()
inline char ch() {
static char buf[1 << 21], *p1 = buf, *p2 = buf;
return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2)
? EOF
: *p1++;
}
inline int in {
int s = 0, f = 1;
char x;
for (x = getchar(); x < '0' || x > '9'; x = getchar())
if (x == '-') f = -1;
for (; x >= '0' && x <= '9'; x = getchar())
s = (s << 1) + (s << 3) + (x & 15);
return f == 1 ? s : -s;
}
} // namespace IO
using namespace IO;
const int A=4e5+5;
const int K=1e5;
int n,m;
int head[A],tot_road;
struct Road{
int nex,to;
}road[2*A];
inline void edge(int x,int y){
road[++tot_road]={
head[x],y};head[x]=tot_road;
}
int dep[A],f[A],top[A],son[A],sz[A];
inline void DFS1(int fa,int x){
f[x]=fa,dep[x]=dep[fa]+1,sz[x]=1;
for(int y=head[x];y;y=road[y].nex){
int z=road[y].to;
if(z==fa) continue;
DFS1(x,z);
sz[x]+=sz[z];
if(sz[z]>sz[son[x]]) son[x]=z;
}
return;
}
inline void DFS2(int x){
if(son[x]){
top[son[x]]=top[x];
DFS2(son[x]);
}
for(int y=head[x];y;y=road[y].nex){
int z=road[y].to;
if(top[z]) continue;
top[z]=z;
DFS2(z);
}
return;
}
inline void tree_cut(){
DFS1(0,1);
top[1]=1;
DFS2(1);
return;
}
inline int lca(int x,int y){
while(top[x]<