代码模板
代码模板大全
数据结构
线段树
标记永久化版本。
区间修改+区间查询
struct Segment_Tree
{
struct node
{
int l, r, sum, lazy;
}tr[N << 4];
void push_up(int u)
{
tr[u].sum = tr[u << 1].sum + tr[u << 1 | 1].sum;
}
void build(int u, int l, int r)
{
tr[u].l = l, tr[u].r = r;
if(l == r){
tr[u].sum = a[l];
return ;
}
int mid = (l + r) / 2;
build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
push_up(u);
}
void update(int u, int l, int r, int k)
{
if(l <= tr[u].l && tr[u].r <= r){
tr[u].lazy += k;
return ;
}
tr[u].sum += (min(r, tr[u].r) - max(l, tr[u].l) + 1) * k;
int mid = (tr[u].l + tr[u].r) >> 1;
if(l <= mid) update(u << 1, l, r, k);
if(r > mid) update(u << 1 | 1, l, r, k);
}
int query(int u, int l, int r)
{
if(l <= tr[u].l && tr[u].r <= r) {
return tr[u].sum + (tr[u].r - tr[u].l + 1) * tr[u].lazy;
}
int res = (min(r, tr[u].r) - max(l, tr[u].l) + 1) * tr[u].lazy;
int mid = (tr[u].l + tr[u].r) >> 1;
if(l <= mid) res += query(u << 1, l, r);
if(r > mid) res += query(u << 1 | 1, l, r);
return res;
}
}seg;
区间乘法/区间加法+区间查询
struct node
{
int l, r, sum, add, mul;
}tree[N << 4];
int a[N], p;
void pushup(int u)
{
tree[u].sum = (tree[lson].sum + tree[rson].sum) % p;
}
void build(int u, int l, int r)
{
if (l == r) tree[u] = {l, r, a[l], 0, 1};
else
{
tree[u] = {l, r, 0, 0, 1};
int mid = (l + r) >> 1;
build(lson, l, mid), build(rson, mid + 1, r);
pushup(u);
}
}
void cal(node &t, int add, int mul)
{
t.sum = (t.sum * mul + (t.r - t.l + 1) * add) % p;
t.add = (t.add * mul + add) % p;
t.mul = (t.mul * mul) % p;
}
void pushdown(int u)
{
cal(tree[lson], tree[u].add, tree[u].mul);
cal(tree[rson], tree[u].add, tree[u].mul);
tree[u].add = 0;
tree[u].mul = 1;
}
void update(int u, int l, int r, int add, int mul)
{
if(l <= tree[u].l && tree[u].r <= r) cal(tree[u], add, mul);
else {
pushdown(u);
int mid = (tree[u].l + tree[u].r) >> 1;
if(l <= mid) update(lson, l, r, add, mul);
if(r > mid) update(rson, l, r, add, mul);
pushup(u);
}
}
int query(int u, int l, int r)
{
if(l <= tree[u].l && tree[u].r <= r) return tree[u].sum;
pushdown(u);
int mid = (tree[u].l + tree[u].r) >> 1;
int res = 0;
if(l <= mid) res += query(lson, l, r);
if(r > mid) res = (res + query(rson, l, r)) % p;
return res;
}
区间最值
struct node{
ll mmax,l,r;
ll tag1,tag2;//修改,加
}t[N<<2];
ll n,q,a[N];
void up(ll k){
t[k].mmax=max(t[k<<1].mmax,t[k<<1|1].mmax);
}
void rev(ll k,ll x,ll y){
if(x==1e9+1){
t[k].tag2+=y;
t[k].mmax+=y;
}
else{
t[k].tag1=x;
t[k].tag2=y;
t[k].mmax=x+y;
}
}
void pd(ll k){
rev(k<<1,t[k].tag1,t[k].tag2);
rev(k<<1|1,t[k].tag1,t[k].tag2);
t[k].tag1=1e9+1;
t[k].tag2=0;
}
/*void downtag1(ll k){
if(t[k].tag1!=1e9+1){
t[k<<1].mmax=t[k<<1].tag1=t[k].tag1;
t[k<<1].tag2=0;
t[k<<1|1].mmax=t[k<<1|1].tag1=t[k].tag1;
t[k<<1|1].tag2=0;
t[k].tag1=1e9+1;
}
}
void downtag2(ll k){
t[k<<1].tag2+=t[k].tag2;
t[k<<1].mmax+=t[k].tag2;
t[k<<1|1].tag2+=t[k].tag2;
t[k<<1|1].mmax+=t[k].tag2;
t[k].tag2=0;
}*/
void build(ll k,ll l,ll r){
t[k].l=l,t[k].r=r,t[k].tag1=1e9+1;
if(l==r){
t[k].mmax=a[l];
return ;
}
ll mid=(l+r)>>1;
build(k<<1,l,mid);build(k<<1|1,mid+1,r);
up(k);
}
void change1(ll k,ll l,ll r,ll x){
if(t[k].l>=l && t[k].r<=r){
t[k].mmax=x;
t[k].tag1=x,t[k].tag2=0;
return ;
}
pd(k);
//downtag1(k),downtag2(k);
ll mid=(t[k].l+t[k].r)>>1;
if(l<=mid) change1(k<<1,l,r,x);
if(r>mid) change1(k<<1|1,l,r,x);
up(k);
}
void change2(ll k,ll l,ll r,ll x){
if(t[k].l>=l && t[k].r<=r){
t[k].mmax+=x;
t[k].tag2+=x;
return ;
}
pd(k);
//downtag1(k),downtag2(k);
ll mid=(t[k].l+t[k].r)>>1;
if(l<=mid) change2(k<<1,l,r,x);
if(r>mid) change2(k<<1|1,l,r,x);
up(k);
}
ll query(ll k,ll l,ll r){
if(t[k].l>=l && t[k].r<=r) return t[k].mmax;
pd(k);
//downtag1(k),downtag2(k);
ll mid=(t[k].l+t[k].r)>>1;
ll ans=-1e18;
if(l<=mid) ans=max(ans,query(k<<1,l,r));
if(r>mid) ans=max(ans,query(k<<1|1,l,r));
return ans;
}
可持久化线段树
单点修改
struct node
{
int l, r;
int lch, rch;
int v;
};
vector<node> tr;
int rt[N], a[N];
inline int build(int l, int r)
{
if(l == r) tr.push_back({l, r, -1, -1, a[l]});
else
{
int mid = (l + r) >> 1;
int lch = build(l, mid), rch = build(mid + 1, r);
tr.push_back({l, r, lch, rch, 0});
}
return tr.size() - 1;
}
inline int update(int u, int loc, int val)
{
if(tr[u].l == tr[u].r)
{
tr.push_back({tr[u].l, tr[u].r, -1, -1, val});
}
else
{
int mid = (tr[u].l + tr[u].r) >> 1;
int lch = tr[u].lch, rch = tr[u].rch;
if(loc <= mid) lch = update(tr[u].lch, loc, val);
if(loc > mid) rch = update(tr[u].rch, loc, val);
tr.push_back({tr[u].l, tr[u].r, lch, rch, 0});
}
return tr.size() - 1;
}
inline int query(int u, int loc)
{
if(tr[u].l == tr[u].r) return tr[u].v;
int mid = (tr[u].l + tr[u].r) >> 1;
if(loc <= mid) return query(tr[u].lch, loc);
if(loc > mid) return query(tr[u].rch, loc);
}
int main()
{
int n = read, m = read;
for(int i = 1;i <= n;i ++ )
{
a[i] = read;
}
rt[0] = build(1, n);
for(int i = 1;i <= m;i ++ )
{
int v = read, op = read, loc = read;
if(op == 1)
{
int val = read;
rt[i] = update(rt[v], loc, val);
}
else
{
cout << query(rt[v], loc) << endl;
rt[i] = rt[v];
}
}
return 0;
}
查询 k 小值
struct node
{
int l, r, sum;
}tr[N << 5];
int a[N], b[N], rt[N], cnt;
int update(int u, int l, int r, int x)
{
int new_ = ++cnt;
tr[new_].l = tr[u].l, tr[new_].r = tr[u].r, tr[new_].sum = tr[u].sum + 1;
int mid = (l + r) / 2;
if(l < r)
{
if(x <= mid) tr[new_].l = update(tr[u].l, l, mid, x);
else tr[new_].r = update(tr[u].r, mid + 1, r, x);
}
return new_;
}
int query(int u, int v, int l, int r, int k)
{
if(l == r) return l;
int x = tr[tr[v].l].sum - tr[tr[u].l].sum; // 提取 [l, r] 线段树
int mid = (l + r) >> 1;
if(k <= x) return query(tr[u].l, tr[v].l, l, mid, k);
else return query(tr[u].r, tr[v].r, mid + 1, r, k - x);
}
int main()
{
int n = read, m = read;
for(int i = 1;i <= n;i ++ ) a[i] = read, b[i] = a[i];
// 离散化 B
sort(b + 1, b + 1 + n);
int len = unique(b + 1, b + 1 + n) - b - 1;
for(int i = 1;i <= n;i ++ ) {
int x = lower_bound(b + 1, b + 1 + len, a[i]) - b;
rt[i] = update(rt[i - 1], 1, len, x);
}
while(m -- )
{
int x = read, y = read, k = read;
cout << b[query(rt[x - 1], rt[y], 1, len, k)] << endl;
}
return 0;
}
平衡树
并查集
int find(int x)
{
if(f[x] == x) return x;
return f[x] = find(f[x]);
}
/*
合并:f[find(a)] = find(b);
查询:find(a) == find(b)
*/
分块
区间查询+区间修改
void update(int x,int y,int k)
{
int l = pos[x],r = pos[y];
if(l == r){
for(int i = x;i <= y;i ++ ){
a[i] +=k;
}
sum[l] += k * (y - x + 1);
}
else{
for(int i = l + 1;i < r;i ++ ) add[i] += k;
for(int i = x;i <= ed[l];i ++ ) a[i] += k;
sum[l] += k * (ed[l] - x + 1);
for(int i = st[r];i <= y;i ++ ) a[i] += k;
sum[r] += k * (y - st[r] + 1);
}
}
int query(int x,int y)
{
long long ans = 0;
int l = pos[x],r = pos[y];
if(l == r){
for(int i = x;i <= y;i ++ ){
ans += a[i];
}
ans += add[l] * (y - x + 1);
}
else{
for(int i = l + 1;i < r;i ++ ) ans += sum[i] + (ed[i] - st[i] + 1) * add[i];
for(int i = x;i <= ed[l];i ++ ) ans += a[i];
ans += add[l] * (ed[l] - x + 1);
for(int i = st[r];i <= y;i ++ ) ans += a[i];
ans += add[r] * (y - st[r] + 1);
}
return ans;
}
signed main()
{
int n, m;
cin >> n >> m;
for(int i = 1;i <= n;i ++ )
{
cin >> a[i];
}
int block = sqrt(n);
int cnt = n / block;
if(n % block) cnt ++ ;
for(int i = 1;i <= cnt;i ++ ){
st[i] = (i - 1) * block + 1;
ed[i] = i * block;
}
ed[cnt] = n;
for(int i = 1;i <= n;i ++ ) pos[i] = (i - 1) / block + 1;
for(int i = 1;i <= cnt;i ++ ){
for(int j = st[i];j <= ed[i];j ++ ){
sum[i] += a[j];
}
}
while(m -- )
{
int op, x, y, k;
cin >> op ;
if(op == 1)
{
cin>>x>>y>>k;
update(x, y, k);
}
else {
cin >> x >> y;
cout <<query(x, y) << endl;
}
}
return 0;
}
区间修改+区间大于小于
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+5;
int n,q;
int a[N],b[N];
int block,tot;
int L[N],R[N];
int x,y,k;
int lazy[N];
int ans;
int belong[N];
void init(){
block=sqrt(n);
tot=n/block;
if(n%block) tot++;
for(int i=1;i<=tot;i++){
L[i]=(i-1)*block+1;
R[i]=i*block;
}
R[tot]=n;
for(int i=1;i<=n;i++){
belong[i]=(i-1)/block+1;
}
for(int i=1;i<=tot;i++){
sort(b+L[i],b+R[i]+1);
}
}
void change(){
if(belong[x]==belong[y]){
for(int i=x;i<=y;i++){
a[i]+=k;
}
for(int i=L[belong[x]];i<=R[belong[x]];i++){
b[i]=a[i];
}
sort(b+L[belong[x]],b+R[belong[x]]+1);
}
else{
for(int i=x;i<=R[belong[x]];i++) a[i]+=k;
for(int i=L[belong[y]];i<=y;i++) a[i]+=k;
for(int i=belong[x]+1;i<=belong[y]-1;i++){
lazy[i]+=k;
}
for(int i=L[belong[x]];i<=R[belong[x]];i++) b[i]=a[i];
for(int i=L[belong[y]];i<=R[belong[y]];i++) b[i]=a[i];
sort(b+L[belong[x]],b+R[belong[x]]+1);
sort(b+L[belong[y]],b+R[belong[y]]+1);
}
}
void query(){
if(belong[x]==belong[y]){
for(int i=x;i<=y;i++){
if(lazy[belong[x]]+a[i]>=k) ans++;
}
return;
}
else{
for(int i=x;i<=R[belong[x]];i++){
if(lazy[belong[x]]+a[i]>=k) ans++;
}
for(int i=L[belong[y]];i<=y;i++){
if(lazy[belong[y]]+a[i]>=k) ans++;
}
for(int i=belong[x]+1;i<=belong[y]-1;i++){
int l=L[i],r=R[i],temp=0;
int mid=0;
while(l<=r){
mid=(l+r)>>1;
if(b[mid]+lazy[i]>=k){
r=mid-1;
temp=R[i]-mid+1;
}
else{
l=mid+1;
}
}
ans+=temp;
}
}
}
int main(){
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
b[i]=a[i];
}
init();
while(q--){
char c;
cin>>c;
scanf("%d%d%d",&x,&y,&k);
if(c=='M'){
change();
}
if(c=='A'){
query();
printf("%d\n",ans);
ans=0;
}
}
}
ST
inline int query(int l, int r)
{
int mid = log2(r - l + 1);
return max(f[l][mid], f[r - (1 << mid) + 1][mid]);
}
int main()
{
int n = read, m = read;
for(int i = 1;i <= n;i ++ )
{
f[i][0] = read;
}
for(int j = 1;j <= (log(n) / log(2));j ++ ){
for(int i = 1;i <= n - (1 << j) + 1;i ++ )
{
f[i][j] = max(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]);
}
}
while(m -- )
{
cout << query(read, read) << endl;
}
return 0;
}
树套树
图论
拓扑排序
queue <int> Q;
void toposort() {
for(int i = 1; i <= n; i++) {
if(deg[i] == 0) {
printf("%d ", i);
Q.push(i);
}
}
while(Q.size()) {
int x = Q.front(); Q.pop();
for(int i = Head[x]; i; i = Next[i]) {
deg[to[i]]--;
if(deg[to[i]] == 0) {
printf("%d ", to[i]);
Q.push(to[i]);
}
}
}
}
最小生成树
prim
kruskal
次小生成树
最短路
dijkstra
前向星
int dijkstra()
{
memset(dist, 0x3f, sizeof dist);
dist[1] = 0;
priority_queue<PII, vector<PII>, greater<PII>> heap;
heap.push({0, 1});
while (heap.size())
{
auto t = heap.top();
heap.pop();
int ver = t.second, distance = t.first;
if (st[ver]) continue;
st[ver] = true;
for (int i = h[ver]; i != -1; i = ne[i])
{
int j = e[i];
if (dist[j] > dist[ver] + w[i])
{
dist[j] = dist[ver] + w[i];
heap.push({dist[j], j});
}
}
}
if (dist[n] == 0x3f3f3f3f) return -1;
return dist[n];
}
vector
void dijkstra(int s)
{
priority_queue<PII, vector<PII>, greater<PII> > q;
q.push({0, s});
memset(vis, false, sizeof(vis)), memset(dist, 0x3f, sizeof(dist));
dist[s] = 0;
while(q.size())
{
PII cur = q.top(); q.pop();
int u = cur.second, w = cur.first;
if(vis[u]) continue;
vis[u] = 1;
for(int i = 0;i < g[u].size();i ++ ){
int v = g[u][i].first;
if(dist[v] > dist[u] + g[u][i].second){
dist[v] = dist[u] + g[u][i].second;
q.push({dist[v], v});
}
}
}
}
spfa
void spfa()
{
memset(dist, 0x3f, sizeof dist);
queue<int> q;
q.push(1);
dist[1] = 0;
vis[1] = true;
while(q.size()){
int u = q.front(); q.pop();
// cout << u << endl;
vis[u] = false;
for(int i = 0;i < g[u].size();i ++ ){
int v = g[u][i].first, w = g[u][i].second;
if(dist[v] > dist[u] + w){
dist[v] = dist[u] + w;
if(!vis[v]){
q.push(v); vis[v] = true;
}
}
}
}
}
floyd
void fl(){
for(int k=1;k<=n;k++){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++)
{
d[i][j]=min(d[i][j],d[i][k]+d[k][j]);
}
}
}
}
最长路
spfa
建图时 c 变 -c;t 变 -t。
判负环
spfa
bool spfa()
{
queue<int> q;
for(int i = 1;i <= n;i ++ ){
vis[i] = true;
q.push(i);
}
while(q.size()){
int u = q.front(); q.pop();
// cout << u << endl;
vis[u] = false;
for(int i = 0;i < (int)g[u].size();i ++ ){
int v = g[u][i].first, w = g[u][i].second;
if(dist[v] > dist[u] + w){
dist[v] = dist[u] + w;
cnt[v] = cnt[u] +1;
if(cnt[v] >= n) return false;
if(!vis[v]){
q.push(v); vis[v] = true;
}
}
}
}
return true;
}
传递闭包
普通 floyd
for(int k = 1;k <= n;k ++ ){
for(int i = 1;i <= n;i ++ ){
for(int j = 1;j <= n;j ++ ){
g[i][j] |= g[i][k] && g[k][j];
}
}
}
bitset 优化
bitset<N> g[N];
for(int k = 1;k <= n;k ++ ){
for(int i = 1;i <= n;i ++ ){
if(g[i][k]) g[i] |= g[k];
}
}
差分约束
k 短路
tarjan
缩点
void tarjan(int u)
{
low[u] = dfn[u] = ++t;
vis[u] = true;
st.push(u);
for(int i = 0;i < g[u].size();i ++ ){
int v = g[u][i];
if(!dfn[v]) {
tarjan(v);
low[u] = min(low[u], low[v]);
}
else if(vis[v]) low[u] = min(low[u], dfn[v]);
}
if(low[u] == dfn[u])
{
cnt ++ ;
int k;
do
{
k = st.top(); st.pop();
sum[cnt] += a[k];
f[k] = cnt;
vis[k] = false;
}while(k != u);
}
}
for(int i = 1;i <= n;i ++ ){
if(!dfn[i]) tarjan(i);
}
for(int u = 1;u <= n;u ++ ){
for(int i = 0;i < g[u].size();i ++ ){
int v = g[u][i];
if(f[v] != f[u]){
g1[f[u]].push_back(f[v]);
}
}
}
最小环
dijkstra
floyd
网络流
分层图
备注:暂时还没怎么刷到这类题,先贴一道题吧。
[P4568 JLOI2011] 飞行路线 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
const int inf = INT_MAX;
typedef pair<int, int> PII;
int n, m, k, s, t;
int d[N][11];
struct node
{
int u, v;
};
vector<node> g[N];
bool vis[N];
void dijkstra()
{
priority_queue<PII, vector<PII>, greater<PII> > q;
for(int i = 0;i <= k;i ++ ) d[s][i] = 0;
for(int i = 0;i <= k;i ++ )
{
q.push(make_pair(0, s));
while(q.size())
{
int x = q.top().second; q.pop();
if(vis[x]) continue;
vis[x] = true;
for(int j = 0;j < g[x].size();j ++ )
{
int y = g[x][j].u;
int f = 0;
if(i && d[y][i] > d[x][i - 1])
{
d[y][i] = d[x][i - 1];
f = 1;
}
if(d[y][i] > d[x][i] + g[x][j].v)
{
d[y][i] = d[x][i] + g[x][j].v;
f = 1;
}
if(f == 1) q.push(make_pair(d[y][i], y));
}
}
memset(vis, false, sizeof(vis));
}
}
int main(){
cin >> n >> m >> k;
cin >> s >> t;
for(int i = 1;i <= m;i ++ )
{
int a, b, c;
cin >> a >> b >> c;
g[a].push_back({b, c});
g[b].push_back({a, c});
}
for(int i = 0;i < n;i ++ )
{
for(int j = 0;j <= k;j ++ )
{
d[i][j] = inf;
}
}
dijkstra();
int ans = inf;
for(int i = 0;i <= k;i ++ ) ans = min(ans, d[t][i]);
cout << ans << endl;
return 0;
}
树
树链剖分
仅给出区间的操作,如果更换更换线段树即可,见上。
struct Segment_Tree
{
struct node
{
int l, r, sum, lazy;
}tr[N << 2];
void push_up(int u)
{
tr[u].sum = tr[u << 1].sum + tr[u << 1 | 1].sum;
}
void build(int u, int l, int r)
{
tr[u].l = l, tr[u].r = r;
if(l == r){
tr[u].sum = a[l]; tr[u].sum %= p;
return ;
}
int mid = (l + r) >> 1;
build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
push_up(u);
}
void update(int u, int l, int r, int k)
{
if(l <= tr[u].l && tr[u].r <= r){
tr[u].lazy += k;
return ;
}
tr[u].sum += (min(r, tr[u].r) - max(l, tr[u].l) + 1) * k;
int mid = (tr[u].l + tr[u].r) >> 1;
if(l <= mid) update(u << 1, l, r, k);
if(r > mid) update(u << 1 | 1, l, r, k);
}
int query(int u, int l, int r)
{
if(l <= tr[u].l && tr[u].r <= r)
{
return (tr[u].sum + (tr[u].r - tr[u].l + 1) * tr[u].lazy) % p;
}
int res = (min(tr[u].r, r) - max(tr[u].l, l) + 1) * tr[u].lazy;
int mid = (tr[u].l + tr[u].r) >> 1;
if(l <= mid) res += query(u << 1, l, r);
if(r > mid) res += query(u << 1 | 1, l, r);
return res % p;
}
}seg;
struct TreePou
{
void update(int x, int y, int val)
{
val %= p;
while(top[x] != top[y]){
if(dep[top[x]] < dep[top[y]]) swap(x, y);
seg.update(1, id[top[x]], id[x], val);
x = fa[top[x]];
}
if(dep[x] > dep[y]) swap(x, y);
seg.update(1, id[x], id[y], val);
}
int query(int x, int y)
{
int ans = 0;
while(top[x] != top[y]){
if(dep[top[x]] < dep[top[y]]) swap(x, y);
ans += seg.query(1, id[top[x]], id[x]);
ans %= p;
x = fa[top[x]];
}
if(dep[x] > dep[y]) swap(x, y);
ans += seg.query(1, id[x], id[y]);
return ans % p;
}
void tupdate(int x, int y)
{
seg.update(1, id[x], id[x] + size[x] - 1, y);
}
int tquery(int x)
{
return seg.query(1, id[x], id[x] + size[x] - 1);
}
}tp;
void dfs1(int u, int f, int deep)
{
dep[u] = deep;
fa[u] = f;
size[u] = 1;
int maxn = -1;
for(int i = 0;i < g[u].size();i ++ )
{
int v = g[u][i];
if(v == f) continue;
dfs1(v, u, deep + 1);
size[u] += size[v];
if(size[v] > maxn) {
maxn = size[v];
son[u] = v;
}
}
}
void dfs2(int u, int topfa)
{
id[u] = ++cnt;
top[u] = topfa;
a[cnt] = w[u];
if(!son[u]) return ;
dfs2(son[u], topfa);
for(int i = 0;i < g[u].size();i ++ ){
int v = g[u][i];
if(v == fa[u] || v == son[u]){
continue;
}
dfs2(v, v);
}
}
LCA
倍增
void dfs(int u, int fa)
{
dep[u] = dep[fa] + 1;
f[u][0] = fa;
for(int i = 1;(1 << i) <= dep[u];i ++ )
{
f[u][i] = f[f[u][i - 1]][i - 1];
}
for(int i = 0;i < g[u].size();i ++){
int v = g[u][i];
if(v == fa) continue;
f[v][0] = u;
dfs(v, u);
}
}
int LCA(int x, int y)
{
if(dep[x] < dep[y]) swap(x, y);
for(int i = 20;i >= 0;i -- )
{
if(dep[f[x][i]] >= dep[y]){
x = f[x][i];
}
}
if(x == y) return x;
for(int i = 20;i >= 0;i -- )
{
if(f[x][i] != f[y][i]){
x = f[x][i], y = f[y][i];
}
}
return f[x][0];
}
树链剖分
void dfs1(int u, int f, int deep)
{
dep[u] = deep;
fa[u] = f;
size[u] = 1;
int maxn = -1;
for(int i = 0;i < g[u].size();i ++ )
{
int v = g[u][i];
if(v == f) continue;
dfs1(v, u, deep + 1);
size[u] += size[v];
if(size[v] > maxn) {
maxn = size[v];
son[u] = v;
}
}
}
void dfs2(int u, int topfa)
{
id[u] = ++cnt;
top[u] = topfa;
a[cnt] = w[u];
if(!son[u]) return ;
dfs2(son[u], topfa);
for(int i = 0;i < g[u].size();i ++ ){
int v = g[u][i];
if(v == fa[u] || v == son[u]){
continue;
}
dfs2(v, v);
}
}
int LCA(int x,int y)
{
while(top[x] != top[y]){
if(dep[top[x]] < dep[top[y]]) swap(x, y);
x = fa[top[x]];
}
if(dep[x] > dep[y]) return y;
return x;
}
树的重心
树的直径
树上计数
树的点分治
杂项
IO
#pragma GCC optimize(3)
#pragma GCC target("avx")
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
#pragma GCC optimize("-fgcse")
#pragma GCC optimize("-fgcse-lm")
#pragma GCC optimize("-fipa-sra")
#pragma GCC optimize("-ftree-pre")
#pragma GCC optimize("-ftree-vrp")
#pragma GCC optimize("-fpeephole2")
#pragma GCC optimize("-ffast-math")
#pragma GCC optimize("-fsched-spec")
#pragma GCC optimize("unroll-loops")
#pragma GCC optimize("-falign-jumps")
#pragma GCC optimize("-falign-loops")
#pragma GCC optimize("-falign-labels")
#pragma GCC optimize("-fdevirtualize")
#pragma GCC optimize("-fcaller-saves")
#pragma GCC optimize("-fcrossjumping")
#pragma GCC optimize("-fthread-jumps")
#pragma GCC optimize("-funroll-loops")
#pragma GCC optimize("-fwhole-program")
#pragma GCC optimize("-freorder-blocks")
#pragma GCC optimize("-fschedule-insns")
#pragma GCC optimize("inline-functions")
#pragma GCC optimize("-ftree-tail-merge")
#pragma GCC optimize("-fschedule-insns2")
#pragma GCC optimize("-fstrict-aliasing")
#pragma GCC optimize("-fstrict-overflow")
#pragma GCC optimize("-falign-functions")
#pragma GCC optimize("-fcse-skip-blocks")
#pragma GCC optimize("-fcse-follow-jumps")
#pragma GCC optimize("-fsched-interblock")
#pragma GCC optimize("-fpartial-inlining")
#pragma GCC optimize("no-stack-protector")
#pragma GCC optimize("-freorder-functions")
#pragma GCC optimize("-findirect-inlining")
#pragma GCC optimize("-fhoist-adjacent-loads")
#pragma GCC optimize("-frerun-cse-after-loop")
#pragma GCC optimize("inline-small-functions")
#pragma GCC optimize("-finline-small-functions")
#pragma GCC optimize("-ftree-switch-conversion")
#pragma GCC optimize("-foptimize-sibling-calls")
#pragma GCC optimize("-fexpensive-optimizations")
#pragma GCC optimize("-funsafe-loop-optimizations")
#pragma GCC optimize("inline-functions-called-once")
#pragma GCC optimize("-fdelete-null-pointer-checks")
#pragma GCC optimize(2)
namespace IO
{
template<typename T>
inline T read(T x)
{
T opt = 1, sum = 0;
char ch = getchar();
while(!isdigit(ch)) opt = (ch == '-') ? -1 : 1, ch = getchar();
while( isdigit(ch)) sum = (sum << 1) + (sum << 3) + (ch ^ 48), ch = getchar();
return opt * sum;
}
}
#define read IO::read(0)
inline void put(int x)
{
if (x > 9) put(x / 10);
putchar(x % 10 + 48);
}
二分
三分
根号分治
模拟退火
备注
更新日志
Update 2024.7.18 建立文档
Update 2024.7.19 优化排版 + 更新dijkstra / lca