背景
我々は2点間の距離を見つける必要がある木のために、多くの人々の最初の反応は、LCAにあります
ただし、変更はそれが追加しない場合はどうなりますか?私たちは木のセクションを使用することができます
オペレーティング
基本的な変数
重さ:サブツリーのサイズ
ヘビー息子:最も重要なの息子です、
ライト息子:息子ではない重いです
重鎖:息子で構成される重鎖
思想
分割統治のパスに基づいて、
重鎖を維持するために、ツリーラインでは、
証明の複雑さ
私たちは、現在のポイントのuを設定し、現在のポイントの親ノードがVであります
、V uは光側の偶数エッジをするかの
重量がV Uの息子ではないことをこのショー
これは、ことを意味\(size_v> 2 * size_u \ )
しかしながら、Nの合計のポイントの合計数、
特定の側鎖までの上に光\(log_n \) A
したがって、最高の複雑\(O(log_n)\)
vがある場合はサイドにウエイト側は、Uを接続しました
説明のuを重く息子、
したがって、VのU側が重い側に接続する必要があります
そして、我々は、上記ツリーラインは、重鎖の複雑さを維持するために使用された\(O(log_n)\)
重鎖定数と光側は、光側まで接続されている\(log_n \)項目ので、重鎖の最大\(log_n \)条
合計時間の複雑さがある\(O(log_nlog_n)\)
ボード
struct tree_chain_split
{
#define MAXN 100005
struct node
{
int l;
int r;
int lazy;
int val;
}tre[4*MAXN];
void build(int l,int r,int k)
{
tre[k].l=l;
tre[k].r=r;
tre[k].lazy=0;
tre[k].val=0;
if(l==r)
return;
int mid=(l+r)>>1;
build(l,mid,k<<1);
build(mid+1,r,k<<1|1);
}
void pushdown(int k)
{
if(tre[k].lazy==0)
return;
tre[k<<1].lazy+=tre[k].lazy;
tre[k<<1|1].lazy+=tre[k].lazy;
tre[k<<1].val+=tre[k].lazy*(tre[k<<1].r-tre[k<<1].l+1);
tre[k<<1|1].val+=tre[k].lazy*(tre[k<<1|1].r-tre[k<<1|1].l+1);
tre[k].lazy=0;
}
void change_poi(int pos,int k,int add)
{
if(pos>tre[k].r||pos<tre[k].l)
return;
if(tre[k].l==tre[k].r)
{
tre[k].val=tre[k].val+add;
return;
}
pushdown(k);
change_poi(pos,k<<1,add);
change_poi(pos,k<<1|1,add);
tre[k].val=tre[k<<1].val+tre[k<<1|1].val;
}
void change_int(int l,int r,int k,int add)
{
if(l>tre[k].r||tre[k].l>r)
return;
if(l<=tre[k].l&&tre[k].r<=r)
{
tre[k].val=tre[k].val+add*(tre[k].r-tre[k].l+1);
tre[k].lazy=tre[k].lazy+add;
return;
}
pushdown(k);
change_int(l,r,k<<1,add);
change_int(l,r,k<<1|1,add);
tre[k].val=tre[k<<1].val+tre[k<<1|1].val;
}
int query(int l,int r,int k)
{
if(l>tre[k].r||tre[k].l>r)
return 0;
if(l<=tre[k].l&&tre[k].r<=r)
return tre[k].val;
pushdown(k);
return query(l,r,k<<1)+query(l,r,k<<1|1);
}
int cnt;
int w[MAXN];
int fa[MAXN];
int id[MAXN];
int siz[MAXN];
int top[MAXN];
int dep[MAXN];
int wson[MAXN];
vector<int> g[MAXN];
#undef MAXN
void addedge(int u,int v)
{
g[u].push_back(v);
}
void dfs1(int u)
{
siz[u]=1;
dep[u]=dep[fa[u]]+1;
int maxx=-1;
int _ind=0;
for(int i=0;i<g[u].size();i++)
{
int v=g[u][i];
if(v!=fa[u])
{
fa[v]=u;
dfs1(v);
siz[u]+=siz[v];
if(siz[v]>maxx)
{
maxx=siz[v];
_ind=v;
}
}
}
wson[u]=_ind;
}
void dfs2(int u,int top_chain)
{
top[u]=top_chain;
id[u]=++cnt;
change_poi(cnt,1,w[u]);
if(!wson[u])
return;
dfs2(wson[u],top_chain);
for(int i=0;i<g[u].size();i++)
{
int v=g[u][i];
if(v!=fa[u]&&v!=wson[u])
dfs2(v,v);
}
}
void init(int len)
{
cnt=0;
build(1,len,1);
dfs1(rt);
dfs2(rt,rt);
}
void change_int(int x,int y,int add)
{
while(top[x]!=top[y])
{
if(dep[top[x]]>dep[top[y]])
swap(x,y);
change_int(id[top[y]],id[y],1,add);
y=fa[top[y]];
}
if(dep[x]>dep[y])
swap(x,y);
change_int(id[x],id[y],1,add);
}
int query(int x,int y)
{
int ret=0;
while(top[x]!=top[y])
{
if(dep[top[x]]>dep[top[y]])
swap(x,y);
ret=ret+query(id[top[y]],id[y],1);
y=fa[top[y]];
}
if(dep[x]>dep[y])
swap(x,y);
ret=ret+query(id[x],id[y],1);
return ret;
}
void change_rot(int x,int add)
{
change_int(id[x],id[x]+siz[x]-1,1,add);
}
int query_rot(int x)
{
return query(id[x],id[x]+siz[x]-1,1);
}
}tre;