树状数组
略
线段树
略
平衡树
inline int newnode(int k){
int u=++tot;key[tot]=rnd(),val[tot]=k;
siz[tot]=1;return tot;
}
inline void pushup(int u){
siz[u]=siz[lc(u)]+siz[rc(u)]+1;
}
inline void split(int u,int &r1,int &r2,int k){
if(!u){r1=r2=0;return;}
if(val[u]<=k){//这是<=
r1=u;split(rc(u),rc(r1),r2,k);
}
else r2=u,split(lc(u),r1,lc(r2),k);
pushup(u);
}
inline void merge(int &u,int r1,int r2){
if(!r1||!r2){u=r1+r2;return;}
if(key[r1]<key[r2]){
u=r1,merge(rc(u),rc(r1),r2);
}
else u=r2,merge(lc(u),r1,lc(r2));
pushup(u);
}
inline int find(int u,int k){
while(siz[lc(u)]+1!=k){
if(siz[lc(u)]>=k)
u=lc(u);
else k-=siz[u]-siz[rc(u)],u=rc(u);
}
return u;
}
inline void insert(int k){
int u=newnode(k),r1,r2;
split(rt,r1,r2,k);
merge(r1,r1,u);
merge(rt,r1,r2);
}
inline void delet(int k){
int r1,r2,r3;
split(rt,r1,r2,k-1);
split(r2,r2,r3,k);
merge(r2,lc(r2),rc(r2));
merge(r1,r1,r2);
merge(rt,r1,r3);
}
inline int rank(int k){
int r1,r2;
split(rt,r1,r2,k-1);
int res=siz[r1]+1;
merge(rt,r1,r2);
return res;
}
inline int getval(int k){
return val[find(rt,k)];
}
inline int pre(int k){
int r1,r2;
split(rt,r1,r2,k-1);
int u=find(r1,siz[r1]);
merge(rt,r1,r2);
return val[u];
}
inline int nxt(int k){
int r1,r2;
split(rt,r1,r2,k);
int u=find(r2,1);
merge(rt,r1,r2);
return val[u];
}
LCT
inline bool isrc(int u){
return rc(fa[u])==u;
}
inline bool isrt(int u){
if(!fa[u])return 1;
return lc(fa[u])!=u&&rc(fa[u])!=u;
}
inline void pushup(int u){
val[u]=a[u];
if(lc(u))val[u]+=val[lc(u)];
if(rc(u))val[u]+=val[rc(u)];
}
inline void pushdown(int u){
if(!rev[u])return;
swap(lc(u),rc(u));
if(lc(u))rev[lc(u)]^=1;
if(rc(u))rev[rc(u)]^=1;
rev[u]=0;
}
inline void rotate(int v){
int u=fa[v],z=fa[u];
int t=rc(u)==v;
if(!isrt(u))son[z][rc(z)==u]=v;//判断
fa[v]=z;
son[u][t]=son[v][t^1],fa[son[v][t^1]]=u;
son[v][t^1]=u,fa[u]=v;
pushup(u),pushup(v);//顺序
}
inline void splay(int u){
q[q[0]=1]=u;
for(int v=u;!isrt(v);v=fa[v])q[++q[0]]=fa[v];
for(int i=q[0];i;i--)pushdown(q[i]);//先pushdown
while(!isrt(u)){
if(!isrt(fa[u])){
if(isrc(u)==isrc(fa[u]))rotate(fa[u]);
else rotate(u);
}
rotate(u);
}
pushup(u);
}
inline void access(int u){
for(int v=0;u;v=u,u=fa[u]){
splay(u),rc(u)=v;
if(v)fa[v]=u;
pushup(u);
}
}
inline int findrt(int u){
access(u),splay(u);
while(pushdown(u),lc(u))u=lc(u);//pushdown
splay(u);return u;
}
inline void makert(int u){
access(u),splay(u),rev[u]^=1;
}
inline void link(int u,int v){
makert(u),fa[u]=v;
}
inline void cut(int u,int v){
makert(u),access(v),splay(v);
lc(v)=fa[u]=0,pushup(v);
}
inline int query(int u,int v){
makert(u),access(v),splay(v);return val[v];
}
维护子树
multiset<int>chain[N];//注意是multiset
inline int fir(int u){
return chain[u].size()?*chain[u].rbegin():-inf;
}
inline void access(int u){
for(int v=0;u;v=u,u=fa[u]){
splay(u);
if(rc(u))chain[u].insert(lmx[rc(u)]);
if(v)chain[u].erase(chain[u].find(lmx[v]));
rc(u)=v;
pushup(u);
}
}
表求(四倍空间)
注意二维哪一维在前(二维寻址常数优化())
void dfs(int u,int fa){
st[0][++dfn]=u;pos[u]=dfn;
for(int e=adj[u];e;e=nxt[e]){
int v=to[e];
if(v==fa)continue;
dep[v]=dep[u]+1;
dfs(v,u),st[0][++dfn]=u;
}
}
void init(){
dfs(1,0);lg[0]=-1;
for(int i=1;i<=dfn;i++)lg[i]=lg[i>>1]+1;
for(int i=1;(1<<i)<=dfn;i++){
for(int j=1;j+(1<<i)-1<=dfn;j++){
int x1=st[i-1][j],x2=st[i-1][j+(1<<(i-1))];
st[i][j]=dep[x1]>dep[x2]?x2:x1;
}
}
}
inline int ask(int u,int v){
int x=pos[u],y=pos[v];
if(x>y)swap(x,y);
int t=lg[y-x+1];
int x1=st[t][x],x2=st[t][y-(1<<t)+1];
return dep[x1]>dep[x2]?x2:x1;
}
void dfs(int u,int f){
st[0][++dfn]=dis[u],pos[u]=dfn;
for(int e=adj[u];e;e=nxt[e]){
int v=to[e];
if(v==f)continue;
dis[v]=dis[u]+1;
dfs(v,u);
st[0][++dfn]=dis[u];
}
}
inline void init(){
dfs(1,0),lg[0]=-1;
for(int i=1;i<=dfn;i++)lg[i]=lg[i>>1]+1;
for(int i=1;(1<<i)<=dfn;i++){
for(int j=1;j+(1<<i)-1<=dfn;j++){
st[i][j]=min(st[i-1][j],st[i-1][j+(1<<(i-1))]);
}
}
}
inline int dist(int u,int v){
int x=pos[u],y=pos[v];
if(x>y)swap(x,y);
int t=lg[y-x+1];
return dis[u]+dis[v]-2*min(st[t][x],st[t][y-(1<<t)+1]);
}
长剖
(注意的范围以及边界(最好每次多开大点但相应数组就要开))
int *f[N],tmp[N],*id=tmp;
void dfs1(int u,int fa){
for(int e=adj[u];e;e=nxt[e]){
int v=to[e];
if(v==fa)continue;
dfs1(v,u);
if(dep[v]>dep[son[u]])son[u]=v;
}
dep[u]=dep[son[u]]+1;
}
void dfs2(int u,int fa){
if(son[u]){f[son[u]]=f[u]+1,dfs2(son[u],u);}
for(int e=adj[u];e;e=nxt[e]){
int v=to[e];
if(v==fa||v==son[u])continue;
f[v]=id,id+=dep[v],dfs2(v,u);
for(int i=0;i<dep[v];i++)calc....;
}
}
int main(){
dfs1(1,0);
f[1]=id,id+=dep[1];
dfs2(1,0);
}
虚树
(注意)
inline void solve(){
stk[top=1]=a[1];
for(int i=2;i<=num;i++){
int lca=Lca(stk[top],a[i]);
while(dfn[lca]<dfn[stk[top]]){
if(dfn[lca]>=dfn[stk[top-1]]){
G2.addedge(lca,stk[top--]);
if(stk[top]!=lca)stk[++top]=lca;
break;
}
G2.addedge(stk[top-1],stk[top]),top--;
}
stk[++top]=a[i];
}
while(top>1)G2.addedge(stk[top-1],stk[top]),top--;
solve(),clear();
}
倍增求注意
动态点分治:
inline int query(int u,int k){
int res=0;
for(int i=u;i;i=fa[i]){
res+=f1[i].query(k-dist(i,u));
}
for(int i=u;fa[i];i=fa[i]){
res-=f2[i].query(k-dist(fa[i],u));
}
return res;
}
注意计算一个是和当前一个是和
一个是判当前有没有一个是父亲有没有
细节:
Kruscal重构树
重构树要开2倍空间
()
struct edge{
int u,v,w;
friend inline bool operator <(const edge &a,const edge &b){
return a.w>b.w;
}
}e[N];
int tot,lc[N],rc[N],fa[N],f[N][22],val[N],g[N];//2倍空间
inline int find(int x){
return fa[x]==x?fa[x]:fa[x]=find(fa[x]);
}
void dfs(int u){
for(int i=1;i<=20;i++)f[u][i]=f[f[u][i-1]][i-1];
if(u<=n){//
g[u]=dis[u];return;
}
dfs(lc[u]),dfs(rc[u]),g[u]=min(g[lc[u]],g[rc[u]]);
}
inline void kruscal(){
sort(e+1,e+m+1);
for(int i=1,cnt=0;i<=m&&cnt<n-1;i++){
int f1=find(e[i].u),f2=find(e[i].v);
if(f1!=f2){
fa[f1]=fa[f2]=fa[++tot]=tot;
val[tot]=e[i].w;
lc[tot]=f1,rc[tot]=f2;
f[f1][0]=f[f2][0]=tot;cnt++;
}
}
dfs(tot);
}
int get(int u,int p){
for(int i=20;~i;i--){
if(fa[u][i]&&val[f[u][i]]>p)u=f[u][i];//神tm高速缓存优化三维寻址
}
return g[u];
}