父节点、子节点、子树、祖先、后代、兄弟、根节点、叶节点、路径等
Matrix-Tree定理
-Prim算法
-Kruskal算法
部分维护动态图的题目可通过离线处理转化为维护最小生成树
-可通过递归处理树的重心来完成动态树分治
加权重心与平权重心求法类似
顾名思义,树上最长的路径
简单的求法:先从一点求出最远点,再以该点求出其最远点,则这两点之间的路径为一条直径
树的中心为直径的中点(不一定在某个节点上,也可能在某条边上,如果在某条边上,则所有直径经过该边)
基于倍增的lca算法,分别求出每个点的 2i 祖先, O(n) 时间可以求出 2i+1 祖先。
分别求出每个点到根的距离,则两点距离为改距离和减去两倍lca到根的距离。
由Matrix-Tree原理得: n 个点的无向完全图的生成树个数为 nn−2
n 个结点的二叉树的个数为卡特兰数列的第 n 项
-维护树的dfs序
-树链剖分
可以处理子树修改问题
-点分治
-边分治
-树分块
-Link-Cut-Tree
涉及到子树修改的则需要使用Top-Tree(然而不会写)
先找出基环再对树进行处理,多数情况下需要删掉基环上的边以转化为树
每条边最多属于一个环的无向联通图
可以在树的算法上进行一定的扩展来处理仙人掌
下面是部分算法的代码实现
#include
using namespace std;
typedef long long ll;
typedef double db;
const int inf=0x3f3f3f3f;
int getint()
{
int f=1,g=0;char c=getchar();
while(c<'0' || c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0' && c<='9')g=(g<<3)+(g<<1)+c-'0',c=getchar();
return f*g;
}
namespace Tree_Theory{
namespace Link_Cut_Tree{
//bzoj某题
const int maxn=100005;
const int mod=51061;
typedef unsigned int uint;
#define lc ch[x][0]
#define rc ch[x][1]
int n;
int ch[maxn][2];
int pre[maxn];
int size[maxn];
bool root[maxn];
bool rev[maxn];
uint sum[maxn];
uint val[maxn];
uint at[maxn];//at for Add Tags
uint mt[maxn];//mt for Multiply Tags
void modify(int x,int m,int a)
{
if(!x)return;
val[x]=(val[x]*m+a)%mod;
sum[x]=(sum[x]*m+a*size[x])%mod;
at[x]=(at[x]*m+a)%mod;
mt[x]=(mt[x]*m)%mod;
}
void up(int x)
{
if(!x)return;
sum[x]=(sum[lc]+sum[rc]+val[x])%mod;
size[x]=(size[lc]+size[rc]+1)%mod;
}
void push_down(int x)
{
if(rev[x])
{
rev[lc]^=1;
rev[rc]^=1;
swap(lc,rc);
rev[x]=0;
}
int m=mt[x];
int a=at[x];
mt[x]=1;
at[x]=0;
if(m!=1 || a!=0)
{
modify(lc,m,a);
modify(rc,m,a);
}
}
void rotate(int x)
{
int y=pre[x];
int f=(ch[y][0]==x);
push_down(y);
push_down(x);
pre[x]=pre[y];
ch[y][!f]=ch[x][f];
pre[ch[x][f]]=y;
if(root[y])
{
root[y]=false;
root[x]=true;
}
else
{
ch[pre[y]][ch[pre[y]][1]==y]=x;
}
pre[y]=x;
ch[x][f]=y;
up(y);
up(x);
}
void splay(int x)
{
push_down(x);
while(!root[x])
{
int y=pre[x],z=pre[y];
push_down(z);
push_down(y);
push_down(x);
if(root[y])
{
rotate(x);
}
else
{
int f=(ch[z][0]==y);
if(ch[y][f]==x)rotate(x);
else rotate(y);
rotate(x);
}
}
up(x);
}
int access(int x)
{
int t=0;
for(;x;x=pre[t=x])
{
splay(x);
root[rc]=true;
root[rc=t]=false;
up(x);
}
return t;
}
bool check(int x,int y)
{
while(pre[x])x=pre[x];
while(pre[y])y=pre[y];
return x==y;
}
void make_root(int x)
{
access(x);
splay(x);
rev[x]^=1;
}
void split(int x,int y)//提取从x~y的路径
{
make_root(y);
access(x);
splay(x);
}
void Link(int x,int y)
{
make_root(x);
pre[x]=y;
}
void Cut(int x,int y)
{
make_root(x);
splay(y);
pre[ch[y][0]]=pre[y];
pre[y]=0;
root[ch[y][0]]=true;
ch[y][0]=0;
}
#undef lc
#undef rc
}
namespace Tree_Chain{
//bzoj1036
const int maxn=100005;
struct treenode{
int l,r,sum,max;
}a[maxn<<2];
int tree[maxn],pre[maxn],son[maxn];
int f[maxn],data[maxn];
int size[maxn],top[maxn],deep[maxn];
vector<int> g[maxn];
int n,i,x,y,cnt,q;
char c[10];
int getint()
{
char c=getchar();
int num=0,f=1;
while(c>'9' || c<'0'){if(c=='-')f=-1;c=getchar();}
while(c<='9' && c>='0')num=num*10+c-'0',c=getchar();
return num*f;
}
void add(int u,int v)
{
g[u].push_back(v);
}
void dfs(int k,int father,int d)
{
deep[k]=d;f[k]=father;size[k]=1;
for (int i=0;iint x=g[k][i];if (x==father) continue;
dfs(x,k,d+1);
size[k]+=size[x];
if (!son[k] || size[x] > size[son[k]]) son[k]=x;
}
}
void dfs2(int k,int ancestor)
{
top[k]=ancestor;tree[k]=++cnt;
pre[tree[k]]=k;
if (!son[k]) return;
dfs2(son[k],ancestor);
for (int i=0;iint go=g[k][i];
if (go!=son[k]&&go!=f[k]) dfs2(go,go);
}
}
void build(int k,int l,int r)
{
a[k].l=l;a[k].r=r;
if(l==r)
{
a[k].sum=a[k].max=data[pre[l]];
return;
}
int mid=(l+r)>>1;
int lc=(k<<1);
int rc=lc+1;
build(lc,l,mid);
build(rc,mid+1,r);
a[k].sum=a[lc].sum+a[rc].sum;
a[k].max=max(a[lc].max,a[rc].max);
}
void update(int k,int x,int v)
{
if (a[k].l==a[k].r)
{
a[k].sum+=v;
a[k].max+=v;
return;
}
int mid=(a[k].l+a[k].r)>>1;
int lc=(k<<1);
int rc=lc+1;
if (x<=mid)
update(lc,x,v);
else
update(rc,x,v);
a[k].sum=a[lc].sum+a[rc].sum;
a[k].max=max(a[lc].max,a[rc].max);
}
int sum(int k,int x,int y)
{
if (a[k].l>=x && a[k].r<=y)
{
return a[k].sum;
}
int mid=(a[k].l+a[k].r)>>1,ans=0;
int lc=(k<<1);
int rc=lc+1;
if (x<=mid)
ans+=sum(lc,x,y);
if (y>mid)
ans+=sum(rc,x,y);
a[k].sum=a[lc].sum+a[rc].sum;
a[k].max=max(a[lc].max,a[rc].max);
return ans;
}
int maxnum(int k,int x,int y)
{
if (a[k].l>=x && a[k].r<=y)
{
return a[k].max;
}
int mid=(a[k].l+a[k].r)>>1,o=-inf;
if (x<=mid) o=maxnum(k<<1,x,y);
if (y>mid) o=max(o,maxnum((k<<1)+1,x,y));
a[k].sum=a[k<<1].sum+a[(k<<1)+1].sum;
a[k].max=max(a[k<<1].max,a[(k<<1)+1].max);
return o;
}
int askmax(int x,int y)
{
int f1=top[x],f2=top[y],t,ans=-inf;
while(f1!=f2)
{
if (deep[f1]1,tree[f1],tree[x]));
x=f[f1];f1=top[x];
}
ans= max(ans,(deep[x]>deep[y]) ? maxnum(1,tree[y],tree[x]) : maxnum(1,tree[x],tree[y]));
return ans;
}
int asksum(int x,int y)
{
int f1=top[x],f2=top[y],t,ans=0;
while (f1!=f2)
{
if (deep[f1]sum(1,tree[f1],tree[x]);
x=f[f1];f1=top[x];
}
ans += (deep[x]>deep[y]) ? sum(1,tree[y],tree[x]) : sum(1,tree[x],tree[y]);
return ans;
}
}
}
int main()
{
return 0;
}