虛樹:原樹中給一些點,通過一些lca把它們重新連線在一起建成一棵新樹,相當於對樹進行了化簡。新樹邊上的資訊可以用樹鏈剖分/倍增等維護。
如何建虛樹:
假設給出的點都存在d陣列裡。
對於這些點,按照它們在原樹中的dfs序從小到大排個序。
然後我們建乙個棧,從棧底到棧頂相當於是一條當前虛樹根一直往下走的鏈。
遍歷d陣列,假設當前要加入的點是v,棧頂的點是u,
1.lca(u,v)==u 顯然u還可以往下走,這條鏈還沒完,直接把v入棧,continue。
2.lca(u,v)!=u 這代表著u這顆子樹已經結束了,v是u子樹外的點。設lca(u,v)=w,我們沿著當前維護的這條鏈一直往上走,在棧上相當於是乙個彈棧+建邊的過程,代表著彈出的點往下的那條鏈已經結束了,不會再被更改,直到有乙個點是w或w的祖先為止。此時如果這個點是w則直接把v入棧,反之則先把w入棧,再把v入棧。
注意,入棧時不建邊而在出棧時建,就是為了出棧時鏈才成型的特性。
把dfs序從小到大排序,相當於我們是在dfs樹上中序遍歷了這些點,保證了演算法的正確性。
板子是我自己yy的,過了以下的兩題,如果在其他題目有鍋,歡迎指出qwq。
bzoj2286消耗戰(板子題,可以用來檢驗建樹模板是否正確)
#includeusing namespace std;
#define rep(x,y,z) for (register int x=y; x<=z; x++)
#define downrep(x,y,z) for (register int x=y; x>=z; x--)
#define ms(x,y,z) memset(x,y,sizeof(z))
#define ll long long
#define repedge(x,y) for (register int x=hed[y]; ~x; x=edge[x].nex)
#define repe(x,y) for(register int x=head[y]; ~x; x=e[x].nex)
inline int read()
const int n=250005;
const int maxlg=18;
const int inf=n+1;
int n,m,tin[n],tout[n],tot,dep[n],toc[n],sum,f[n][maxlg+1],g[n][maxlg+1];
int nedge,hed[n],nedge,head[n],d[n],imp[n],st[n];
ll dp[n];
struct edgeedge[n<<1],e[n<<1];
void addedge(int a,int b,int c)
void dfs_1(int k)tout[k]=tot;
}void dfs_2(int k)
}int cmp(int a,int b)
while(tp>1) adde(st[tp-1],st[tp]),tp--;
}int main()
f[1][0]=1; g[1][0]=inf; dfs_1(1);
rep(j,1,maxlg) rep(i,1,n)
scanf("%d",&m); nedge=0; ms(head,-1,head);
rep(i,1,m)
return 0;
}
bzoj3572世界樹(細節賊多的虛樹裸題,不過想清楚再寫就不難了)
具體題解見我的luogu部落格
#includeusing namespace std;
#define rep(x,y,z) for (register int x=y; x<=z; x++)
#define downrep(x,y,z) for (register int x=y; x>=z; x--)
#define ms(x,y,z) memset(x,y,sizeof(z))
#define ll long long
#define repedge(x,y) for (register int x=hed[y]; ~x; x=edge[x].nex)
#define repe(x,y) for(register int x=head[y]; ~x; x=e[x].nex)
#define mp make_pair
#define pr pair#define fr first
#define se second
inline int read()
const int n=300005;
const int maxlg=18;
int n,m,nedge,hed[n],sz[n],tin[n],tout[n],dep[n],f[n][maxlg+1],tot;
int nedge,head[n],d[n],st[n],tmp[n],imp[n],toc[n],sum,val[n],ans[n],lg[(1<1)&&(dep[st[tp-1]]>dep[w])) adde(st[tp-1],st[tp]),tp--;
adde(w,st[tp]); tp--; if ((!tp)||(st[tp]!=w)) st[++tp]=w; st[++tp]=v;
} while(tp>1) adde(st[tp-1],st[tp]),tp--; return st[tp];
}void dfs_2(int k)
}void dfs_3(int k)
}int main()
rep(i,0,maxlg) lg[(1直接虛樹+dp就可以了。
#includeusing namespace std;
#define rep(x,y,z) for (register int x=y; x<=z; x++)
#define downrep(x,y,z) for (register int x=y; x>=z; x--)
#define ms(x,y,z) memset(x,y,sizeof(z))
#define ll long long
#define repedge(x,y) for (register int x=hed[y]; ~x; x=edge[x].nex)
#define repe(x,y) for (register int x=head[y]; ~x; x=e[x].nex)
inline int read()
const int n=1000005;
const int maxlg=20;
int n,m,nedge,hed[n],tot,tin[n],tout[n],fa[n][maxlg+1],dep[n];
int nedge,head[n],toc[n],cnt,d[n],imp[n],st[n];
ll sum[n],calc[n],len[n],f[n],f2[n],g[n],g2[n];
struct edgeedge[n<<1];
struct nodee[n];
void addedge(int a,int b)
void dfs_1(int k)tout[k]=tot;
}bool isancestor(int x,int y)
int getlca(int x,int y)
int cmp(int x,int y)
while(tp>1) adde(st[tp-1],st[tp]),tp--; return st[tp];
}const ll inf=1e9;
void dfs_2(int k)
}int main()
fa[1][0]=1; dfs_1(1);
rep(j,1,maxlg) rep(i,1,n) fa[i][j]=fa[fa[i][j-1]][j-1];
scanf("%d",&m); nedge=0; ms(head,-1,head);
rep(i,1,m)
return 0;
}
線段樹 模板 例題
模板 以區間和為例。ll ls ll p ll rs ll p void push up ll p void build ll p,ll l,ll r ll mid l r 1 build ls p l,mid build rs p mid 1 r push up p void f ll p,ll ...
字典樹模板及例題
字典樹 time limit 1000ms memory limit 65536kb problem description 遇到單詞不認識怎麼辦?查字典啊,已知字典中有n個單詞,假設單詞都是由小寫字母組成。現有m個不認識的單詞,詢問這m個單詞是否出現在字典中。input 含有多組測試用例。第一行輸...
全排列 模板和例題
1.直接使用 stl 中的 next permutation 實現全排列 includeusing namespace std intmain sort a,a 4 do printf n while next permutation a,a 4 2.遞迴求全排列 n 個元素的全排列 不斷將每個元素...