【模板】最近公共祖先(LCA)
水温逐渐升高
#include<bits/stdc++.h>
using namespace std;
const int N = 5e5 + 10;
int n,m,s;
vector<int> ed[N];
int dp[N][21],dep[N];
void dfs(int x,int fa){
for(int i = 1;i <= 20;i++)
dp[x][i] = dp[dp[x][i - 1]][i - 1];
for(auto y:ed[x]){
if(y == fa) continue;
dp[y][0] = x;
dep[y] = dep[x] + 1;
dfs(y,x);
}
}
int lca(int x,int y){
if(dep[y] > dep[x]) swap(x,y);
for(int i = 20;i >= 0;i--){
if(dep[dp[x][i]] >= dep[y]) x = dp[x][i];
}
if(x == y) return x;
for(int i = 20;i >= 0;i--){
if(dp[x][i] != dp[y][i]) x = dp[x][i],y = dp[y][i];
}
return dp[x][0];
}
int main(){
ios::sync_with_stdio(false);//写了using namespace std;
cin >> n >> m >> s;
for(int i = 1;i <= n - 1;i++){
int u,v;cin >> u >> v;
ed[u].push_back(v);
ed[v].push_back(u);
}
dp[s][0] = s;
dep[s] = 1;
dfs(s,s);
for(int i = 1;i <= m;i++){
int x,y;cin >> x >> y;
cout << lca(x,y) << endl;
}
}
【模板】线段树 1
我什么时候写过这么全的线段树?我都不记得
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define lson (x << 1)
#define rson (x << 1 | 1)
const int MAXN = 5e5 + 10;
int a[MAXN];
class tree{
public:
ll sum[MAXN*4];//代表的和
ll ma[MAXN*4];//代表的最大值
ll mi[MAXN*4];//代表的最小值
bool fadd[MAXN*4];//是否启用标签
ll ladd[MAXN*4];//加法标签
bool fturn[MAXN*4];
ll lturn[MAXN*4];//变换标签
ll l[MAXN*4],r[MAXN*4];
void build(int _l,int _r,int x)
{
l[x] = _l,r[x] = _r;
if(_l == _r)
{
sum[x] = a[_l];
ma[x] = a[_l];
mi[x] = a[_l];
}
else
{
int mid = (_l+_r)/2;
build(_l,mid,lson);
build(mid + 1,_r,rson);
update(x);
}
}
void add(int _l,int _r,int x,int v){
if(_l <= l[x] && _r >= r[x])
{
ladd[x] += v;
fadd[x] = 1;
ma[x] += v;
mi[x] += v;
sum[x] += v*(r[x] - l[x] + 1);
}
else
{
down(x);
int mid = (l[x] + r[x]) / 2;
if(_l <= mid)
add(_l,_r,lson,v);
if(_r >= mid + 1)
add(_l,_r,rson,v);
update(x);
}
}
void turn(int _l,int _r,int x,int v){
if(_l <= l[x] && _r >= r[x])
{
lturn[x] = v;
fturn[x] = 1;
fadd[x] = 0;
ladd[x] = 0;
ma[x] = v;
mi[x] = v;
sum[x] = v * (r[x] - l[x] + 1);
}
else
{
down(x);
int mid = (l[x] + r[x]) / 2;
if(_l <= mid)
turn(_l,_r,lson,v);
if(_r >= mid + 1)
turn(_l,_r,rson,v);
update(x);
}
}
void update(int x){
ma[x] = max(ma[lson],ma[rson]);
mi[x] = min(mi[lson],mi[rson]);
sum[x] = sum[lson] + sum[rson];
}
void down(int x){
if(fturn[x])
{
fturn[lson] = fturn[rson] = 1;
lturn[lson] = lturn[rson] = lturn[x];
ma[lson] = ma[rson] = lturn[x];
mi[lson] = mi[rson] = lturn[x];
sum[lson] = lturn[x]*(r[lson]-l[lson]+1);
sum[rson] = lturn[x]*(r[rson]-l[rson]+1);
fadd[lson] = fadd[rson] = 0;
fturn[x] = 0;
}
if(fadd[x])
{
fadd[lson] = fadd[rson] = 1;
ma[lson] += ladd[x];
ma[rson] += ladd[x];
mi[lson] += ladd[x];
mi[rson] += ladd[x];
sum[lson] += ladd[x]*(r[lson]-l[lson]+1);
sum[rson] += ladd[x]*(r[rson]-l[rson]+1);
ladd[lson] += ladd[x];
ladd[rson] += ladd[x];
fadd[lson] = fadd[rson] = 1;
fadd[x] = 0;
ladd[x] = 0;
}
}
ll findma(int _l,int _r,int x)
{
if(_l <= l[x] && _r >= r[x])
return ma[x];
else
{
down(x);
int mid = (l[x] + r[x]) / 2;
ll ma = 0;
if(_l <= mid)
ma = findma(_l,_r,lson);
if(_r >= mid + 1)
ma = max(ma,findma(_l,_r,rson));
update(x);
return ma;
}
}
ll findmi(int _l,int _r,int x)
{
if(_l <= l[x] && _r >= r[x])
return mi[x];
else
{
down(x);
int mid = (l[x] + r[x]) / 2;
ll mi = 1e9 + 10;
if(_l <= mid)
mi = findmi(_l,_r,lson);
if(_r >= mid + 1)
mi = min(mi,findmi(_l,_r,rson));
update(x);
return mi;
}
}
ll findsum(int _l,int _r,int x)
{
if(_l <= l[x] && _r >= r[x])
return sum[x];
else
{
down(x);
int mid = (l[x] + r[x]) / 2;
ll sum = 0;
if(_l <= mid)
sum += findsum(_l,_r,lson);
if(_r >= mid + 1)
sum += findsum(_l,_r,rson);
return sum;
update(x);
}
}
}tr;
int main()
{
int n,q;cin >> n >> q;
for(int i = 1;i <= n;i++)
cin >> a[i];
tr.build(1,n,1);
for(int i = 1;i <= q;i++)
{
int op;cin >> op;
if(op == 1)
{
int _l,_r,x;cin >> _l >> _r >> x;
tr.add(_l,_r,1,x);
}
else if(op == 2)
{
int _l,_r;cin >> _l >> _r;
cout << tr.findsum(_l,_r,1) << endl;
}
else
{
int _l,_r;cin >> _l >> _r;
if(op == 3)
cout << tr.findsum(_l,_r,1) << endl;
else if(op == 4)
cout << tr.findma(_l,_r,1) << endl;
else
cout << tr.findmi(_l,_r,1) << endl;
}
}
}
【模板】KMP 字符串匹配
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
int nex[N];
void fnex(string s){
nex[0] = -1;
int n = s.size(),ptop = -1,i = 0;
while(i < n){
if(ptop == -1 || s[i] == s[ptop])
nex[++i] = ++ptop;
else
ptop = nex[ptop];
}
}
int main(){
string s1,s2;cin >> s1 >> s2;
fnex(s2);
int n = s1.size(),m = s2.size();
int i = 0,pos = 0;
while(i < n){
if(pos == m){
cout << i - m + 1 << endl;
pos = nex[pos];
}else if(pos == -1 || s2[pos] == s1[i])
pos++,i++;
else
pos = nex[pos];
}
if(pos == m)
cout << i - m + 1 << endl;
for(int i = 1;i <= m;i++)
cout << nex[i] << ' ';
}
【模板】矩阵加速(数列)
结合矩阵快速幂
[ a b c ] ∗ [ t 1 t 2 t 3 t 4 t 5 t 6 t 7 t 8 t 9 ] = [ t 1 ∗ a + t 4 ∗ b + t 7 ∗ c t 2 ∗ a + t 5 ∗ b + t 8 ∗ c t 3 ∗ a + t 6 ∗ b + t 9 ∗ c ] \left[\begin{matrix} a&b&c \end{matrix}\right] *\left[\begin{matrix}t_1 &t_2&t_3\\t_4&t_5&t_6\\t_7&t_8&t_9\end{matrix}\right]= \left[\begin{matrix}t_1*a+t_4*b+t_7*c &t_2*a+t_5*b+t_8*c&t_3*a+t_6*b+t_9*c\end{matrix}\right] [abc]∗ t1t4t7t2t5t8t3t6t9 =[t1∗a+t4∗b+t7∗ct2∗a+t5∗b+t8∗ct3∗a+t6∗b+t9∗c]
因此可以令 t 4 , t 8 , t 3 , t 9 t4,t8,t3,t9 t4,t8,t3,t9为1从而得到
[ a b c ] ∗ [ 0 0 1 1 0 0 0 1 1 ] = [ b c a + c ] \left[\begin{matrix} a&b&c \end{matrix}\right] *\left[\begin{matrix}0 &0&1\\1&0&0\\0&1&1\end{matrix}\right]= \left[\begin{matrix}b &c&a+c\end{matrix}\right] [abc]∗ 010001101 =[bca+c]
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 4,mod = 1e9 + 7;
struct jz{
ll a[N][N];
jz(){memset(a,0,sizeof(a));}//构造
jz(bool f){memset(a,0,sizeof(a));//单位矩阵
for(int i = 1;i <= 3;i++)
a[i][i] = 1;
}//构造单位矩阵
jz operator*(const jz &other)const{
jz ans;
for(int i = 1;i <= 3;i++)
for(int j = 1;j <= 3;j++)
for(int k = 1;k <= 3;k++)
ans.a[i][j] = (ans.a[i][j] + a[i][k]*other.a[k][j]) % mod;
return ans;
}
};
jz jzfpow(jz a,ll n){
jz ans(true);
while(n){
if(n&1) ans = (ans*a);
n >>= 1;
a=a*a;
}
return ans;
}
int main(){
jz tem;
tem.a[1][3] = tem.a[2][1] = tem.a[3][2] = tem.a[3][3] = 1;
int t;cin >> t;
while(t--){
int k;cin >> k;
if(k <= 3)
cout << 1 << endl;
else{
jz no = jzfpow(tem,k - 2);
cout << (no.a[1][1] + no.a[1][2] + no.a[1][3]) % mod << endl;
}
}
}