模板大集合 - Part 4

01Trie

const int N = 10000005;
int cnt = 1;
int son[N][2], n, a[N];

void Insert(int k) {
    int now = 0;

    for (int i = 1 << 30; i; i >>= 1) {
        int ch = (k & i) ? 1 : 0;

        if (!son[now][ch])
            son[now][ch] = cnt++;

        now = son[now][ch];
    }
}

int Find(int k) {
    int now = 0;
    int maxn = 0;

    for (int i = 1 << 30; i; i >>= 1) {
        int ch = (k & i) ? 0 : 1;

        if (son[now][ch]) {
            maxn += i;
            now = son[now][ch];
        } else
            now = son[now][!ch];
    }

    return maxn;
}

线段树式01Trie

const int N = 5e5 + 5;
int rt,ls[N * 30],rs[N * 30],sum[N * 30],cnt;
void push_up(int p) {
	sum[p] = sum[ls[p]] + sum[rs[p]];
}

void ins(int &p,int x,int dep) {
	if(!p) p = ++cnt;
	if(dep == -1) {
		sum[p]++;
		return;
	}
	(x >> dep) & 1 ? ins(rs[p],x,dep - 1) : ins(ls[p],x,dep - 1);
	push_up(p);
}

int Find(int &p,int x,int dep,...) {
	if(!p) return 0;
	if(dep == -1) return sum[p];
	int res = 0;
	if((x >> dep) & 1) 
		...,res += Find(rs[p],x,dep - 1,...);
	else 
		...,res += Find(ls[p],x,dep - 1,...);
	return res;
}

拉格朗日插值

这个在 N O I P NOIP NOIP 还是能排上用场的 – NOIP2022 微信步数

非常有趣的根据 n + 1 n + 1 n+1 个点确定 n n n 次函数

P4781 【模板】拉格朗日插值

#include<bits/stdc++.h>
using namespace std;

#define int long long

int rd() {
	int x = 0, w = 1;
	char ch = 0;
	while (ch < '0' || ch > '9') {
		if (ch == '-') w = -1;
		ch = getchar();
	}
	while (ch >= '0' && ch <= '9') {
		x = x * 10 + (ch - '0');
		ch = getchar();
	}
	return x * w;
}

void wt(int x) {
	static int sta[35];
	int f = 1;
	if(x < 0) f = -1,x *= f;
	int top = 0;
	do {
		sta[top++] = x % 10, x /= 10;
	} while (x);
	if(f == -1) putchar('-');
	while (top) putchar(sta[--top] + 48);
}

const int N = 2e3+5,mod = 998244353;

int n,k,x[N],y[N];

int qpow(int x,int k) {
	int res = 1;
	while(k) {
		if(k & 1) res = (res * x) % mod;
		x = (x * x) % mod;
		k >>= 1;
	}
	return res;
}

int inv[N][N];

signed main() {

	n = rd(),k = rd();
	for(int i = 1;i<=n;i++) x[i] = rd(),y[i] = rd();
	int ans = 0;
	
	for(int i = 1;i<=n;i++) 
		for(int j = 1;j<=n;j++) 
			if(i ^ j)
				inv[i][j] = qpow(x[i] - x[j] + mod,mod - 2);

	for(int i = 1;i<=n;i++) {
		int res = 1;
		for(int j = 1;j<=n;j++) 
			if(j ^ i) 
				res = (res * (k - x[j] + mod) % mod * inv[i][j]) % mod;
		ans = (ans + res * y[i] % mod) % mod;
	}

	wt(ans);

	return 0;
}

数位dp

P2657 windy 数

const int N = 15;
int a,b;
int dp[N][N]; //dp[i][j] 第 i 位 数字是 k

void init(){
	// 初始化
	for(int i = 0;i <= 9;i++) dp[1][i] = 1;
	for(int i = 2;i <= 13;i++) {
		for(int j = 0;j<=9;j++) {
			for(int k = 0;k<=j-2;k++) dp[i][j] += dp[i-1][k];
			for(int k = j + 2;k<=9;k++) dp[i][j] += dp[i-1][k];
		}
	}
}

int solve(int x){
	//解决问题
	int d[N];
	memset(d,0,sizeof(d));
	int len = 0,ans = 0;
	while(x) {d[++len] = x%10;x /= 10;}// 拆位
	for(int i = 1;i<len;i++) for(int j = 1;j<=9;j++) ans += dp[i][j]; // 取位数小于该 x 的全集
	// 接下来逼近 x
	for(int i = 1;i<d[len];i++) ans += dp[len][i]; // 取最高位小于概述的全集
	for(int i = len-1;i >= 1;i--) {
		//从最高位往低位探究
		for(int j = 0;j<=min(d[i+1]-2,d[i]-1);j++) ans += dp[i][j]; 
		for(int j = d[i+1]+2;j<d[i];j++) ans += dp[i][j];
		if(d[i] > d[i+1] - 2 && d[i] < d[i+1] + 2) break;
	}
	return ans;
}

instream : a ~ b
outstream : solve(b + 1) - solve(a);
// solve(x) 的计算是左闭右开的

ola质数筛

bool vis[N];
int p[N],top;

void init() {
    vis[1] = true;
    for(int i = 2;i<=1e5;i++) {
        if(!vis[i]) 
            p[++top] = i;
        for(int j = 1;j<=top && p[j] * i <= 1e5;j++) {
            vis[i * p[j]] = true;
            if(i % p[j] == 0) 
                break;
        }
    }
}

轮廓线dp

P4363 [九省联考 2018] 一双木棋 chess

使用的关键在于发现状态数并不多,用 n n n 进制数来表现轮廓的状态

d p dp dp 的 转移 和 轮廓线 息息相关

img

如图,蓝色轮廓线状态只能转移到含一个紫色的状态
因为 $ 1 \leq n,m \leq 10$ 用 11 11 11 进制压缩状态就可以了

轮廓线状态压缩:

ll zip(int *now){
	ll res = 0;
	for(int i = n;i>=1;i--) res = res * 11 + now[i];
	return res; 
}

void unzip(ll S,int *now) {
	for(int i = 1;i<=n;i++) {
		now[i] = S % 11;
		S /= 11; 
	}
}	

AC-Code:

#include<bits/stdc++.h>
using namespace std;

int rd() {
	int x = 0, w = 1;
	char ch = 0;
	while (ch < '0' || ch > '9') {
		if (ch == '-') w = -1;
		ch = getchar();
	}
	while (ch >= '0' && ch <= '9') {
		x = x * 10 + (ch - '0');
		ch = getchar();
	}
	return x * w;
}

void wt(int x) {
	static int sta[35];
	int f = 1;
	if(x < 0) f = -1,x *= f;
	int top = 0;
	do {
		sta[top++] = x % 10, x /= 10;
	} while (x);
	if(f == -1) putchar('-');
	while (top) putchar(sta[--top] + 48);
}

typedef long long ll;

int n,m;
int a[11][11],b[11][11];

unordered_map<ll,ll> dp;

ll zip(int *now){
	ll res = 0;
	for(int i = n;i>=1;i--) res = res * 11 + now[i];
	return res; 
}

void unzip(ll S,int *now) {
	for(int i = 1;i<=n;i++) {
		now[i] = S % 11;
		S /= 11; 
	}
}	

const ll inf = 1e9;

ll dfs(ll S){
	if(dp.count(S)) return dp[S];
	int size = 0;
	int *now = new int[11];
	unzip(S,now);
	for(int i = 1;i<=n;i++) size += now[i];
	int re = (size & 1) ? inf:-inf;
	for(int i = 1;i<=n;i++) {
		if((i == 1 && now[i] < m) || (i != 1 && now[i] < now[i-1])) {
			now[i]++;
			if((size & 1)) re = min((ll)re,dfs(zip(now)) - b[i][now[i]]);
			else re = max((ll)re,dfs(zip(now)) + a[i][now[i]]);
			now[i]--;
		}
	}
	delete now;
	return dp[S] = re;
}

signed main() {
	n = rd(),m = rd();
	for(int i = 1;i<=n;i++) 
		for(int j = 1;j<=m;j++) 
			a[i][j] = rd();
	for(int i = 1;i<=n;i++) 
		for(int j = 1;j<=m;j++) 
			b[i][j] = rd();

	ll ed = 0;
	for(int i = 1;i<=n;i++) ed = ed * 11 + m;
	dp[ed] = 0;
	ll ans = dfs(0);
	wt(ans);
	return 0;
}

BKDR-Hash

P3370 【模板】字符串哈希

AC-code:

#include <bits/stdc++.h>
using namespace std;
#define For(i,a,n) for(register int i = a;i<=n;i++)
#define ull unsigned long long 
const int N = 1e5+6;
ull base[4] = {4969,71011,4339,131};
char s[N];
ull BKDRhash(char *s,int k) {
	ull H = 0;
	while(*s) H = H * base[k] + (*s++);
	return H;
}
ull bn[4][N];
int n;
signed main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);cout.tie(nullptr);
	cin>>n;
	For(i,1,n) {
		cin>>s;
		For(j,3,3) 
			bn[j][i] = BKDRhash(s,j);
	}
	int ans = 0;
	For(j,3,3) sort(bn[j]+1,bn[j] + n + 1);
	For(i,1,n) {
		bool check = true;
		For(j,3,3) if(bn[j][i] == bn[j][i + 1]){check = false;break;} 
		if(check)ans++;
	}
	cout<<ans;
	return 0;
}

路径压缩并查集

code:

const int N = 1005;

int s[N<<1];

int find(int x) {
	if(s[x] ^ x) s[x] = find(s[x]);
	return s[x];
}

void merge(int x,int y) {
	int fx = find(x),fy = find(y);
	s[fy] = fx;
}

Floyd

code:

#include <bits/stdc++.h>
using namespace std;
#define For(i,a,n) for(register int i = a;i<=n;i++)
const int N = 105,INF = 1e9;
int dp[N][N],n,m,u,v,w;
signed main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);cout.tie(nullptr);
	
	cin>>n>>m;
	memset(dp,0x3f,sizeof(dp));
	For(i,1,m) {
		cin>>u>>v>>w;
		dp[u][v] = dp[v][u] = min(dp[u][v],w);
	}
	//floyd
	For(k,1,n) {
		For(i,1,n) {
			For(j,1,n) {
				dp[i][j] = min(dp[i][j],dp[i][k] + dp[j][k]);
			}
		}
	}
	return 0;
}

ST表

code:

#include <bits/stdc++.h>
using namespace std;
#define For(i,a,n) for(register int i = a;i<=n;i++)
#define LOG2(x) __lg(x)

const int N = 1e5 + 10;
int n, m, a[N], x, y, dp[N][25];

void st_init() {
    For(i, 1, n) dp[i][0] = a[i];
    int p = LOG2(n);
    For(k, 1, p) {
        for (int s = 1; s + (1 << k) <= n + 1; s++) {
            dp[s][k] = max(dp[s][k - 1], dp[s + (1 << (k - 1))][k - 1]);
        }
    }
}

int query(int L, int R) {
    int k = LOG2(R - L + 1);
    return max(dp[L][k], dp[R - (1 << k) + 1][k]);
}

signed main() {
    cin >> n >> m;
    For(i, 1, n) cin >> a[i];
    st_init();
    For(i, 1, m) {
        cin >> x >> y;
        cout << query(x, y) << '\n';
    }

    return 0;
}

Spfa

code:

int dis[N],Neg[N];
bool inq[N];
vector<Edge> edge[N];

il bool spfa(int s) {
	For(i,0,N-1) Neg[i] = 0;
	Neg[s] = 1;
	dis[s] = 0;
	queue<int> q;
	q.push(s);
	inq[s] = true;
	while(!q.empty()) {
		int t = q.front();
		q.pop();
		inq[t] = false;
		for(auto i:edge[t]) {
			if(dis[t] + i.w < dis[i.to]) {
				dis[i.to] = dis[t] + i.w;
				if(!inq[i.to]) {
					inq[i.to] = true;
					q.push(i.to);
					Neg[i.to]++;
					if(Neg[i.to] > n) return 1;
				} 
			}
		}
	}
	return 0;
}

Ola路径

code:

#include <bits/stdc++.h>
using namespace std;
#define For(i,a,n) for(register int i = a;i<=n;i++)
#define CIN const int
#define il inline

CIN N = 2e5 + 10;;
int n,m,f,t,posa = 1,del[N],st[N],top; 
vector<int> g[N];
int dg[N],A,B;

il void dfs(int u) {
	for(int i = del[u];i < g[u].size();i = del[u]) {
		del[u]++;
		dfs(g[u][i]);
	}
	st[++top] = u;
}

signed main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);cout.tie(nullptr);
	
	cin>>n>>m;
	For(i,1,m) {
		cin>>f>>t;
		g[f].push_back(t);
		dg[t]--;
		dg[f]++;
	}
	For(i,1,n) sort(g[i].begin(),g[i].end());
	
	For(i,1,n) {
		if(dg[i] == 1) A++,posa = i;
		if(dg[i] == -1) B++;
		if(A > 1||B > 1) cout<<"No",exit(0);
		if(dg[i] > 1|| dg[i] < -1) cout<<"No",exit(0);
	}
	
	if(A != B) cout<<"No",exit(0);
	
	dfs(posa);
	
	for(int i = top;i>=1;i--) cout<<st[i]<<' ';
		
	return 0;
}

差分约束

code:

#include <bits/stdc++.h>
using namespace std;
#define For(i,a,n) for(register int i = a;i<=n;i++)
const int N = 5005,INF = INT_MAX;

struct Edge{
	int to,w;
	Edge(int t,int w) :to(t),w(w) {}
};

int m,n,u,v,w;
int dis[N],Neg[N];
bool inq[N];
vector<Edge> edge[N];

void clear() {
	For(i,0,N-1) edge[i].clear();
	For(i,0,N-1) dis[i] = INF,inq[i] = false;
	m = 0,n = 0,u = 0,v = 0,w = 0;
}

bool spfa(int s) {
	For(i,0,N-1) Neg[i] = 0;
	Neg[s] = 1;
	dis[s] = 0;
	deque<int> q;//SLF 
	q.push_back(s);
	inq[s] = true;
	while(!q.empty()) {
		int t = q.front();
		q.pop_front();
		inq[t] = false;
		for(auto i:edge[t]) {
			if(dis[t] + i.w < dis[i.to]) {
				dis[i.to] = dis[t] + i.w;
				if(!inq[i.to]) {
					inq[i.to] = true;
					if(!q.empty()&&dis[i.to] >= dis[q.front()])q.push_back(i.to);
					else q.push_back(i.to);
					Neg[i.to]++;
					if(Neg[i.to] > n) return 1;
				} 
			}
		}
	}
	return 0;
}

signed main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);cout.tie(nullptr);
	
	clear();
	cin>>n>>m;
	For(i,1,m){
		cin>>v>>u>>w;
		edge[u].push_back(Edge(v,w));
	}
	For(i,1,n) edge[0].push_back(Edge(i,0));
	if(spfa(0)) {
		cout<<"NO\n";
	}
	else For(i,1,n) cout<<dis[i]+5<<' '; 
	
	
	return 0;
}

传递闭包

code:

#include <bits/stdc++.h>
using namespace std;
#define For(i,a,n) for(register int i = a;i<=n;i++)

const int N = 105;

int n,a[N][N];

signed main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);cout.tie(nullptr);
	
	cin>>n;
	For(u,1,n) {
		For(i,1,n) {
			cin>>a[u][i];
		}
	}
	
	For(k,1,n) {
		For(i,1,n) {
			For(j,1,n) {
				a[i][j] |= a[i][k] & a[k][j];
			}
		}
	}
	For(i,1,n) {
		For(j,1,n) {
			cout<<a[i][j] <<' ';
		}
		cout<<'\n';
	}
	
	
	return 0;
}

模意义下乘法逆元

inv!递推法

code:

#include <bits/stdc++.h>
using namespace std;
#define CIN const int
#define il inline
#define LOG2(x) __lg(x)
#define MJY(p) freopen(p".in","r",stdin);freopen(p".out","w",stdout);
#define int long long

CIN N = 3e6+5;
int inv[N],n,p;

signed main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);cout.tie(nullptr);
//	clock_t start,end;
//	start = clock();
	
	cin>>n>>p;
	inv[1] = 1;
	for(int i = 2;i<=n;i++) {
		inv[i] = (p - p / i) * inv[p % i] % p;
	}
	for(int i = 1;i<=n;i++) {
		cout<<inv[i]<<'\n';
	}
	
//	end = clock();
//	cout<<"time = "<<double(end-start)/CLOCKS_PER_SEC<<"s"<<endl;
	
	return 0;
}

exgcd 求法

code:

#include <bits/stdc++.h>
using namespace std;
#define CIN const int
#define il inline
#define LOG2(x) __lg(x)
#define MJY(p) freopen(p".in","r",stdin);freopen(p".out","w",stdout);
#define int long long

void exgcd(int a,int b,int &x,int &y) {
	if(!b) {
		x = 1;
		y = 0;
	}else {
		exgcd(b,a % b,x,y);
		int t = x;
		x = y;
		y = t - a/b * y;
	}
}

int mod_inv(int a,int p) {
	int x,y;
	exgcd(a,p,x,y);
	x = (x % p + p) % p;
	return x;
}

CIN N = 3e6+5;
int n,p,f[N],inv[N];

signed main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);cout.tie(nullptr);
//	clock_t start,end;
//	start = clock();
	cin>>n>>p; 
	f[0] = f[1] = 1;
	for(int i = 2;i<=n;i++) f[i] = f[i-1] * i % p;
	
	inv[n] = mod_inv(f[n],p);
	
	for(int i = n-1;i>=1;i--) inv[i] = inv[i + 1] * (i + 1) % p;

	for(int i = 1;i<=n;i++) cout<<inv[i] * f[i-1] % p<<'\n';
	
//	end = clock();
//	cout<<"time = "<<double(end-start)/CLOCKS_PER_SEC<<"s"<<endl;
	
	return 0;
}

费马小定理法

#include <bits/stdc++.h>
using namespace std;

#define int long long
const int mod = ?;

int qpow(int x,int k) {
	int r = 1;
	while(k) {
		if(k & 1) r = r * x % mod;
		x = (x * x) % mod;
		k >>= 1;
	}
	return r;
}

signed main() {
	int x = rd();
	wt(qpow(x,mod - 1));
}

lucas 定理

code:

const int N = ?;
int fac[N],p;

int qpow(int x,int k) {
	int res = 1;
	while(k) {
		if(k & 1) res = (res * x) % p;
		x = (x *  x) % p;
		k >>= 1;
	}
	return res;
}

int C(int a,int b) {
	if(b > a) return 0;
	return ((fac[a] * qpow(fac[b],p-2)) % p * qpow(fac[a - b],p-2) % p);
}

int lucas(int a,int b) {
	if(!b) return 1;
	return C(a % p,b % p) * lucas(a / p,b / p) % p;
}

signed main(){
	fac[0] = fac[1] = 1;
	for(int i = 2;i<N;i++) fac[i] = fac[i-1] * i % p;
	return 0;
}

拓扑排序

#include <bits/stdc++.h>
using namespace std;
#define For(i,a,n) for(register int i = a;i<=n;i++)

int n,t,deg[105];
vector<int> son[105];
queue<int> q;

signed main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);cout.tie(nullptr);
	
	cin>>n;
	For(i,1,n) {
		while(cin>>t) {
			if(t^0) {
				deg[t]++;
				son[i].push_back(t);
			}else goto EXIT;
		}
		EXIT:;
	}
	
	For(i,1,n) {
		if(deg[i] == 0) {
			cout<<i<<' ';
			q.push(i);
		}
	}
	while(!q.empty()){
		int x = q.front();
		q.pop();
		for(int k:son[x]){
			deg[k]--;
			if(!deg[k]) {
				cout<<k<<' ';
				q.push(k);
			}
		}
	}
	
	
	return 0;
}

LCA

树剖求法

code:

#include<bits/stdc++.h>
using namespace std;
		
int rd() {
	int x = 0, w = 1;
	char ch = 0;
	while (ch < '0' || ch > '9') {
		if (ch == '-') w = -1;
		ch = getchar();
	}
	while (ch >= '0' && ch <= '9') {
		x = x * 10 + (ch - '0');
		ch = getchar();
	}
	return x * w;
}

void wt(int x) {
	static int sta[35];
	int f = 1;
	if(x < 0) f = -1,x *= f;
	int top = 0;
	do {
		sta[top++] = x % 10, x /= 10;
	} while (x);
	if(f == -1) putchar('-');
	while (top) putchar(sta[--top] + 48);
}
const int N = 2e5+5;
int n;
int head[N],nxt[N<<1],to[N<<1],cnt;

void init() {memset(head,-1,sizeof(head));cnt = 0;}
void add(int u,int v) {
	nxt[cnt] = head[u];
	to[cnt] = v;
	head[u] = cnt++;
}

int fa[N],son[N],siz[N],dep[N],top[N];

void dfs1(int x,int f) {
	fa[x] = f;
	siz[x] = 1;
	dep[x] = dep[f] + 1;
	for(int i = head[x];~i;i = nxt[i]) {
		int y = to[i];
		if(y ^ f) {
			dfs1(y,x);
			siz[x] += siz[y];
			if(siz[son[x]] < siz[y]) son[x] = y;
		}
	}
}

void dfs2(int x,int topx) {
	top[x] = topx;
	if(!son[x]) return;
	dfs2(son[x],topx);
	for(int i = head[x];~i;i = nxt[i]) {
		int y = to[i];
		if(y ^ fa[x] && y ^ son[x]) dfs2(y,y);
	}
}

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]];
	}
	return dep[x] < dep[y] ? x : y;
}

signed main() {
	n = rd();
	for(int i = 1;i<n;i++){
		int u = rd(),v = rd();
		add(u,v);add(v,u);
	}
	dfs1(1,0);dfs2(1,1);
	int q = rd();
	while(q--) {
		int x = rd(),y = rd();
		wt(LCA(x,y));
		putchar('\n');
	}
	return 0;
}

倍增求LCA

#include <bits/stdc++.h>
using namespace std;
#define For(i,a,n) for(register int i = a;i<=n;i++)

const int N = 5e5+5;
struct node{
	int t,n;
}edge[N<<1];
int head[N<<1],cnt;

void init(){
	For(i,0,(N<<1)-1) edge[i].n = -1,head[i] = -1;
	cnt = 0;
}

void addedge(int u,int v){
	edge[cnt].t = v;edge[cnt].n = head[u];head[u] = cnt++;
}

int fa[N][20],deep[N];

void dfs(int x,int f) {
	deep[x] = deep[f] + 1;
	fa[x][0] = f;
	for(int i = 1;(1<<i) <= deep[x];i++) fa[x][i] = fa[fa[x][i-1]][i-1];
	for(int i = head[x];~i;i = edge[i].n) if(edge[i].t^f) dfs(edge[i].t,x);
}

int LCA(int x,int y) {
	if(deep[x] < deep[y]) swap(x,y);
	for(int i = 19;i >= 0;i--) if(deep[x] - (1<<i) >= deep[y]) x = fa[x][i];
	if(x == y) return x;
	for(int i = 19;i>=0;i--) if(fa[x][i]^fa[y][i]) x = fa[x][i],y = fa[y][i];
	return fa[x][0];
}	

signed main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);cout.tie(nullptr);
	init();
	int n,m,root;
	cin>>n>>m>>root;
	For(i,1,n-1) {
		int u,v;
		cin>>u>>v;
		addedge(u,v);
		addedge(v,u);
	}
	dfs(root,0);
	while(m--) {
		int a,b;
		cin>>a>>b;
		cout<<LCA(a,b)<<"\n";
	}
	return 0;
}

DFS序求LCA

Alex_Wei 的文章

#include <bits/stdc++.h>
using namespace std;
#define For(i,a,n) for(register int i = a;i<=n;i++)
#define LOG2(x) __lg(x)
const int N = 5e5+5;
int n,m,s,dfn,num[N],dp[19][N];
vector<int> e[N];
int get(int x,int y) {
	return num[x] < num[y] ? x : y;
}

void dfs(int id,int fa) {
	dp[0][num[id] = ++dfn] = fa;
	for(int i:e[id])  {
		if(i^fa) dfs(i,id);
	}
}

int lca(int u,int v) {
	if(u == v) return u;
	if((u = num[u]) > (v = num[v])) swap(u,v);
	int d = LOG2(v - u++);
	return get(dp[d][u],dp[d][v - (1<<d) + 1]);
}

signed main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);cout.tie(nullptr);
	cin>>n>>m>>s;
	for(int i = 2,u,v;i <= n;i++) {
		cin>>u>>v;
		e[u].push_back(v);
		e[v].push_back(u);
	}
	dfs(s,0);
	For(i,1,LOG2(n)) 
		for(int j = 1;j + (1<<i) -1 <= n;j++) 
			dp[i][j] = get(dp[i-1][j],dp[i-1][j + (1<<i-1)]);
	For(i,1,m) {
		int u,v;
		cin>>u>>v;
		cout<<lca(u,v)<<'\n';
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值