Bootstrap

模板大集合 - Part 3

P3810 【模板】三维偏序(陌上花开)

CDQ分治:

#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 = 2e5+5;

struct query{
    int x,y,z,w,ans;
};

bool cmpx(query a,query b) {
    if(a.x == b.x) {
        if(a.y == b.y)
            return a.z < b.z;
        return a.y < b.y;
    }
    return a.x < b.x;
}

bool cmpy(query a,query b) {
    if(a.y == b.y) 
        return a.z < b.z;
    return a.y < b.y;
}
#define lowbit(x) ((x) & (-x))
int n,k,c[N];
query a[N],b[N];

int t[N];

void add(int x,int k) {while(x < N) t[x] += k,x += lowbit(x);}

int ask(int x){int res = 0;while(x > 0) res += t[x],x -= lowbit(x);return res;}

void cdq(int l,int r) {
    if(l == r) return;
    int mid = (l + r) >> 1;
    cdq(l,mid),cdq(mid + 1,r);
    sort(a + l,a + mid + 1,cmpy);
    sort(a + mid + 1,a + r + 1,cmpy);
    int pl = l,pr;
    for(int pr = mid + 1;pr <= r;pr++) {
        while(a[pr].y >= a[pl].y && pl <= mid) 
            add(a[pl].z,a[pl].w),pl++;
        a[pr].ans += ask(a[pr].z);
    }
    for(int i = l;i<pl;i++)   
        add(a[i].z,-a[i].w);
}

signed main() {

    n = rd(),k = rd();
    for(int i = 1;i<=n;i++)
        b[i].x = rd(),b[i].y = rd(),b[i].z = rd();
    sort(b + 1,b + n + 1,cmpx);
    int C = 0,top = 0;
    for(int i = 1;i <= n;i++) {
        C++;
        if(b[i].x != b[i + 1].x || b[i].y != b[i + 1].y || b[i].z != b[i + 1].z) 
            a[++top] = b[i],a[top].w = C,C = 0;
    }
    cdq(1,top);
    for(int i = 1;i<=top;i++) 
        c[a[i].ans + a[i].w - 1] += a[i].w; 
    for(int i = 0;i<n;i++) 
        wt(c[i]),putchar('\n');

	return 0;
}

实用普通模板

借学长 c k a i n ckain ckain 的 实用模板
我为什么不写一个呢?因为我太懒了

原文章

Fast Read & Fast Write

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);
}

Mod_int

template<int Mo> struct mint {
	int x;
	mint(int _x=0) {x=(_x+Mo)%Mo;}
	friend void print(mint a, char ch=0) {printf("%d", a.x); if(ch) putchar(ch);}
	friend mint qpow(mint a, int b) {
		mint re(1); for(; b; b>>=1, a=a*a) if(b&1) re=re*a; return re;
	}
    friend mint qpow(int a,int b) {
		mint re(1);for(; b; b >>= 1,a = (a * a) % Mo) if(b & 1) re = re * a;return re;
	}
	bool operator == (mint a) {return x==a.x;}
	bool operator != (mint a) {return x!=a.x;}
    bool operator == (int a) {return x==a;}
	bool operator != (int a) {return x!=a;}
	bool operator > (mint a) {return x>a.x;}
	bool operator < (mint a) {return x<a.x;}
	bool operator >= (mint a) {return x>=a.x;}
	bool operator <= (mint a) {return x<=a.x;}
    bool operator > (int a) {return x>a;}
	bool operator < (int a) {return x<a;}
	bool operator >= (int a) {return x>=a;}
	bool operator <= (int a) {return x<=a;}
	mint operator - () {return *this * (Mo-1);}
	friend mint operator + (mint a, mint b) {a.x+=b.x; if(a.x>=Mo) a.x-=Mo; return a;}
	friend mint operator - (mint a, mint b) {a.x-=b.x; if(a.x<0) a.x+=Mo; return a;}
	friend mint operator * (mint a, mint b) {return mint(1ll*a.x*b.x%Mo);}
	friend mint operator / (mint a, mint b) {return a*qpow(b, Mo-2);}
    friend mint operator + (mint a, int b) {a.x+=b; a.x = (a.x + b) % Mo; return a;}
	friend mint operator - (mint a, int b) {a.x-=b; a.x = (a.x - b + Mo) % Mo; return a;}
	friend mint operator * (mint a, int b) {return mint(1ll*a.x*b%Mo);}
	friend mint operator / (mint a, int b) {return a*qpow(mint(b), Mo-2);}
	mint operator += (mint a) {return *this=*this+a;}
	mint operator -= (mint a) {return *this=*this-a;}
	mint operator *= (mint a) {return *this=*this*a;}
	mint operator /= (mint a) {return *this=*this/a;}
    mint operator += (int a) {return *this=*this+a;}
	mint operator -= (int a) {return *this=*this-a;}
	mint operator *= (int a) {return *this=*this*a;}
	mint operator /= (int a) {return *this=*this/a;}
};

自定义复数

struct C {
    double r,i;
    C() {r = 0,i = 0;}
    C(double a,double b) {r = a,i = b;}
    friend C operator + (const C &a,const C &b) {return C(a.r + b.r,a.i - b.i);}
    friend C operator - (const C &a,const C &b) {return C(a.r - b.r,a.i - b.i);}
    friend C operator * (const C &a,const C &b) {
		return C(a.r * b.r - a.i * b.i,a.r * b.i + a.i  * b.r);
	}
    void operator += (const C &b) {r += b.r;i += b.i;}
    void operator *= (const C &b) {double t = r;r = r * b.r - i * b.i;i = t * b.i + i * b.r;}
};

LinkFrontStar

const int N = 1e6;
struct edge{
int head[N],nxt[N<<1],to[N<<1],val[N<<1],cnt; 

edge(){memset(head,-1,sizeof(head));}

void addWithVal(int u,int v,int w) {
    nxt[cnt] = head[u];
    to[cnt] = v;
    val[cnt] = w;
    head[u] = cnt++;
}

void addWithoutVal(int u,int v) {
    nxt[cnt] = head[u];
    to[cnt] = v;
    head[u] = cnt++;
}
};

自动拆矩阵

const int K=10, P=998244353;

//!矩阵阶数
int m=8;

struct Mat{
	int c[K][K];
	Mat(bool bas=false){
		mset(c, 0);
		if(bas) for(int i=0; i<m; i++) c[i][i]=1;
	}
	int &operator ()(int i, int j){return c[i][j];}
	int operator ()(int i, int j)const{return c[i][j];}
	//debug
	Mat print(){
		for(int i=0; i<m; i++){
			for(int j=0; j<m; j++){
				debug("%d ", c[i][j]);
			}
			debug("\n");
		}
	}
	//
	Mat operator *(const Mat &o)const{
		Mat re;
		for(int i=0; i<m; i++){
			for(int j=0; j<m; j++){
				for(int k=0; k<m; k++){
					(re(i, j)+=(ll)c[i][k]*o(k, j)%P)%=P;
				}
			}
		}
		return re;
	}
};

mt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count());
template<typename T> T rnr(T l, T r){return l+rng()%(r-l+1);}

vector<Mat> choice;

//!输入矩阵列表
void give_choice(){
}

Mat get_rand_mat(){
	return choice[rnr(0, (int)choice.size()-1)];
}

int state[K][K];

void identify(){
	Mat o=get_rand_mat();
	for(int i=0; i<m; i++){
		for(int j=0; j<m; j++){
			state[i][j]=o(i, j);
		}
	}
	int T=20, TT=500;
	for(int _=1; _<=T; _++){
		o=Mat(true);
		for(int __=1; __<=TT; __++, o=o*get_rand_mat()){
			for(int i=0; i<m; i++){
				for(int j=0; j<m; j++) if(state[i][j]!=-1){
					if(state[i][j]!=o(i, j)) state[i][j]=-1;
				}
			}
		}
	}
}

void print(){
	//矩阵拆解的结果
	printf("\nchanged position:\n");
	for(int i=0; i<m; i++){
		for(int j=0; j<m; j++){
			if(state[i][j]==-1) printf("m%d%d, ", i, j);
		}
	}
	puts("");
	//输入矩阵拆解后的表达
	printf("\nmatrix choice:\n");
	for(int i=0; i<(int)choice.size(); i++){
		printf("Mat %d:\n", i);
		for(int j=0; j<m; j++){
			for(int k=0; k<m; k++) if(state[j][k]==-1){
				printf("m%d%d=%d, ", j, k, choice[i](j, k));
			}
		}
		puts("");
	}
	//单位矩阵拆解后的表达
	printf("Bas:\n");
	for(int j=0; j<m; j++){
		for(int k=0; k<m; k++) if(state[j][k]==-1){
			printf("m%d%d=%d, ", j, k, j==k);
		}
	}
	puts("");
	//矩阵乘法
	printf("\nmatrix and matrix:\n");
	for(int i=0; i<m; i++){
		for(int j=0; j<m; j++) if(state[i][j]==-1){
			printf("re.m%d%d=", i, j);
			bool first=true;
			for(int k=0; k<m; k++){
				if(!state[i][k] || !state[k][j]) continue;
				if(!first) printf("+");
				first=false;
				if(state[i][k]==-1 || state[k][j]==-1){
					state[i][k]==-1 ? printf("m%d%d", i, k) : printf("%d", state[i][k]);
					printf("*");
					state[k][j]==-1 ? printf("o.m%d%d", k, j) : printf("%d", state[k][j]);
				}
				else printf("%d", state[i][k]*state[k][j]);
			}
			printf(",\n");
		}
	}
	//向量乘矩阵
	printf("\nvector and matrix:\n");
	for(int i=0; i<m; i++){
		printf("re.v%d=", i);
		bool first=true, exist=false;
		for(int j=0; j<m; j++){
			if(!state[j][i]) continue;
			exist=true;
			if(!first) printf("+");
			first=false;
			printf("v%d*", j);
			state[j][i]==-1 ? printf("o.m%d%d", j, i) : printf("%d", state[j][i]);
		}
		if(!exist) printf("0");
		printf(",\n");
	}
}

Hash_With_Two_Mod

不得不说 operator []很好用
尤其是用在矩阵上
比如写动态DP时
可以省去很多反直觉的 a.m[][]
直接使用 a[][]

struct Hash{
    const int mod_1 = 1e9+7,mod_2 = 1e9+9;
    int x,y;
    Hash(){}
    Hash(int _x,int _y) {x = _x,y = _y;}
    int operator [](const int pos) {return pos ? y : x;}
    friend Hash operator +(Hash a,Hash b) {
		return Hash((a[0] + b[0]) % a.mod_1,(a[1] + b[1]) % a.mod_2);
	}
    friend Hash operator -(Hash a,Hash b) {
		return Hash((a[0] - b[0] + a.mod_1) % a.mod_1,(a[1] - b[1] + a.mod_2) % a.mod_2);
	}
    friend Hash operator *(Hash a,Hash b) {
		return Hash((a[0] * b[0]) % a.mod_1,(a[1] * b[1]) % b.mod_2);
	} 
    void operator = (Hash a) {x = a.x,y = a.y;}
}base(131,13331);

超级快读

struct FastIO
{
#define get( ) getchar( )
#define put(x) putchar(x)
public:
    inline FastIO &operator >>(char &t)  { 
		t = get(); return *this; 
	}
    inline FastIO &operator >>(char *t)  { 
		while((*t = get()) != '\n') *(++t) = '\0'; 
		return *this; 
	}
    template <typename type>
    inline FastIO &operator >>(type &x)  { 
		x = 0; register int sig = 1; register char ch = get();
        while (ch < 48 || ch > 57) { if (ch == '-') sig = -1; ch = get(); }
		while (ch > 47 && ch < 58) x = (x << 3) + (x << 1) + (ch ^ 48),
        ch = get(); x *= sig; 
		return *this; 
	}
    template <typename type>
    inline FastIO &operator <<(type  x)  {
		if (!x) put('0'); if (x < 0) put('-'), x = -x; static char vec[50];
        register int len = 0; while (x) vec[len++] = x % 10 + '0', x /= 10;
    	while (len--) put(vec[len]); 
		return *this; 
	}
    template <typename type>                                  
    inline FastIO &operator <<(type *t)  {
		for (; *t; t++) put(*t); 
		return *this;
	}
    inline FastIO &operator <<(char  t)  { 
		put(t); 
		return *this;
	}
}IO;

【模板】“动态 DP”&动态树分治

题面:

题目描述

给定一棵 n n n 个点的树,点带点权。

m m m 次操作,每次操作给定 x , y x,y x,y,表示修改点 x x x 的权值为 y y y

你需要在每次操作之后求出这棵树的最大权独立集的权值大小。

输入格式

第一行有两个整数,分别表示结点个数 n n n 和操作个数 m m m

第二行有 n n n 个整数,第 i i i 个整数表示节点 i i i 的权值 a i a_i ai

接下来 ( n − 1 ) (n - 1) (n1) 行,每行两个整数 u , v u, v u,v,表示存在一条连接 u u u v v v 的边。

接下来 m m m 行,每行两个整数 x , y x,y x,y,表示一次操作,修改点 x x x 的权值为 y y y

输出格式

对于每次操作,输出一行一个整数表示答案。

样例 #1
样例输入 #1
10 10
-11 80 -99 -76 56 38 92 -51 -34 47 
2 1
3 1
4 3
5 2
6 2
7 1
8 2
9 4
10 7
9 -44
2 -17
2 98
7 -58
8 48
3 99
8 -61
9 76
9 14
10 93
样例输出 #1
186
186
190
145
189
288
244
320
258
304
提示
数据规模与约定
  • 对于 30 % 30\% 30% 的数据,保证 n , m ≤ 10 n,m\le 10 n,m10
  • 对于 60 % 60\% 60% 的数据,保证 n , m ≤ 1 0 3 n,m\le 10^3 n,m103
  • 对于 100 % 100\% 100% 的数据,保证 1 ≤ n , m ≤ 1 0 5 1\le n,m\le 10^5 1n,m105 1 ≤ u , v , x ≤ n 1 \leq u, v , x \leq n 1u,v,xn − 1 0 2 ≤ a i , y ≤ 1 0 2 -10^2 \leq a_i, y \leq 10^2 102ai,y102

dp 套 dp

首先,因为最大独立集的dp

{ f i , 0 = ∑ j ∈ s o n i max ⁡ ( f j , 0 , f j , 1 ) ; f i , 1 = ∑ j ∈ s o n i f j , 0 ; \begin{align*} \begin{cases} f_{i,0} = \sum_{j \in son_i} \max(f_{j,0},f_{j,1}); \\ f_{i,1} = \sum_{j \in son_i} f_{j,0}; \end{cases} \end{align*} {fi,0=jsonimax(fj,0,fj,1);fi,1=jsonifj,0;

这个 Σ \Sigma Σ 太烦了,我们考虑优化状态

我们将 i i i 的孩子分为重儿子轻儿子

因为有了重链剖分,就有了轻儿子和重儿子之分

我们设 g i , 0 g_{i,0} gi,0 i i i 的轻儿子中可选可不选的最大值, G i , 1 G_{i,1} Gi,1 i i i 的轻儿子都不选的最大值

那么最大独立集的dp

(ps:以下的 j j j i i i 的重儿子)

{ f i , 0 = g i , 0 + max ⁡ ( f j , 0 , f j , 1 ) f i , 1 = g i , 1 + a i + f j , 0 ; \begin{align*} \begin{cases} f_{i,0} = g_{i,0} + \max(f_{j,0},f_{j,1}) \\ f_{i,1} = g_{i,1} + a_i + f_{j,0}; \end{cases} \end{align*} {fi,0=gi,0+max(fj,0,fj,1)fi,1=gi,1+ai+fj,0;

我们发现这个 g i , 1 + a i g_{i,1} + a_i gi,1+ai 很难看,两个式子要尽量类似

所以我们将 a i a_i ai 划分到 g i , 1 g_{i,1} gi,1 中,即将 g i , 1 g_{i,1} gi,1 的定义改为,选该点且轻儿子都不选的最大值

那么最大独立集的dp
{ f i , 0 = g i , 0 + max ⁡ ( f j , 0 , f j , 1 ) f i , 1 = g i , 1 + f j , 0 ; \begin{align*} \begin{cases} f_{i,0} = g_{i,0} + \max(f_{j,0},f_{j,1}) \\ f_{i,1} = g_{i,1} + f_{j,0}; \end{cases} \end{align*} {fi,0=gi,0+max(fj,0,fj,1)fi,1=gi,1+fj,0;

接下来如何做呢?

我们不难发现 max ⁡ \operatorname{max} max 是有结合律的,而矩阵乘法也有

那么,我们再变形

{ f i , 0 = max ⁡ ( g i , 0 + f j , 0 , g i , 0 + f j , 1 ) f i , 1 = max ⁡ ( g i , 1 + f j , 0 , − ∞ ) ; \begin{align*} \begin{cases} f_{i,0} = \max(g_{i,0} + f_{j,0},g_{i,0} + f_{j,1}) \\ f_{i,1} = \max(g_{i,1} + f_{j,0},-\infty); \end{cases} \end{align*} {fi,0=max(gi,0+fj,0,gi,0+fj,1)fi,1=max(gi,1+fj,0,);

那么,我们定义广义矩阵乘法,在链上push_up
广义矩阵乘法:

struct matrix{
int m[2][2];
matrix(){memset(m,-0x3f,sizeof(m));}
matrix(bool flag) {m[0][0] = m[1][1] = 1;}
int* operator [](const int pos) {return m[pos];}
friend matrix operator * (matrix a,matrix b) {
	matrix c;
	for(int k = 0;k<2;k++)
		for(int i = 0;i<2;i++)
			for(int j = 0;j<2;j++)
				c[i][j] = max(c[i][j],a[i][k] + b[k][j]);
	return c;
}
}w[N];

如何设计转移矩阵呢?

$$
\begin{bmatrix}
f_{i,0} \
f_{i,1} \
\end{bmatrix}

\mathrm{U} \times
\begin{bmatrix}
f_{j,0} \
f_{j,1} \
\end{bmatrix}
$$

求出 U \mathrm{U} U 就好了

不难计算,
U = [ g i , 0 g i , 0 g i , 1 − ∞ ] \mathrm{U} = \begin{bmatrix} g_{i,0} & g_{i,0} \\ g_{i,1} & -\infty \end{bmatrix} U=[gi,0gi,1gi,0]

然后是修改链的细节

我们要查询的是每条链汇聚到 root ⁡ \operatorname{root} root 上节点的总 ∗ \color{red}{*}

因为本题初始化 f i , 0 = 0 , f i , 1 = a i f_{i,0} = 0,f_{i,1} = a_i fi,0=0,fi,1=ai,所以直接查询答案矩阵的 g i , 0 g_{i,0} gi,0 g i , 1 g_{i,1} gi,1 就可以了

在修改的时候,我们采取对原矩阵组进行修改,然后让线段树上的对于点直接读取原矩阵组

修改一个点,只会影响到这个链的链头的父亲(因为链头的父亲的矩阵就是由每一条链做 ∗ \color{red}{*} 积来的)

所以我们在修改完后,对链头的父亲进行一次更新(更新的值要查询修改前后整条链的矩阵 ∗ \color{red}{*} 积 )

还有全局平衡二叉树的做法

我是蒟蒻,表示看不懂

请读者自行研究

树剖AC
AC-code:

#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 = 1e5+5;
struct matrix{
int m[2][2];
matrix(){memset(m,-0x3f,sizeof(m));}
matrix(bool flag) {m[0][0] = m[1][1] = 1;}
int* operator [](const int pos) {return m[pos];}
friend matrix operator * (matrix a,matrix b) {
	matrix c;
	for(int k = 0;k<2;k++)
		for(int i = 0;i<2;i++)
			for(int j = 0;j<2;j++)
				c[i][j] = max(c[i][j],a[i][k] + b[k][j]);
	return c;
}
}w[N];
int n,m,a[N],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 F[N][2];
int fa[N],top[N],son[N],siz[N],dep[N],id[N],low[N],_id[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;
		}
	}
}
int num;
void dfs2(int x,int topx) {
	id[x] = ++num;
	_id[num] = x;
	top[x] = topx;
	low[topx] = max(id[x],low[topx]);
	F[x][0] = 0,F[x][1] = a[x];
	w[x][0][0] = w[x][0][1] = 0;
	w[x][1][0] = a[x];
	if(!son[x]) return;
	dfs2(son[x],topx);
	F[x][0] += max(F[son[x]][0],F[son[x]][1]);
	F[x][1] += F[son[x]][0];
	for(int i = head[x];~i;i = nxt[i]) {
		int y = to[i];
		if(y ^ fa[x] && y ^ son[x]){
			dfs2(y,y);
			F[x][0] += max(F[y][0],F[y][1]);
			F[x][1] += F[y][0];
			w[x][0][0] += max(F[y][0],F[y][1]);
			w[x][0][1] = w[x][0][0];
			w[x][1][0] += F[y][0];
		}
	}
}

namespace sgt{
#define ls (p << 1)
#define rs (p << 1 | 1)
#define mid ((pl + pr) >> 1)
matrix t[N<<2];

void push_up(int p) {
	t[p] = t[ls] * t[rs];
}

void build(int p,int pl,int pr) {
	if(pl == pr) {
		t[p] = w[_id[pl]];
		return;
	}
	build(ls,pl,mid);
	build(rs,mid+1,pr);
	push_up(p);
}

void update(int p,int pl,int pr,int k) {
	if(pl == pr) {
		t[p] = w[_id[pl]];
		return;
	}
	if(k <= mid) update(ls,pl,mid,k);
	else update(rs,mid+1,pr,k);
	push_up(p);
}

matrix query(int p,int pl,int pr,int l,int r) {
	if(l <= pl && pr <= r) return t[p];
	if(r <= mid) return query(ls,pl,mid,l,r);
	else if(l > mid) return query(rs,mid+1,pr,l,r);
	else return query(ls,pl,mid,l,r) * query(rs,mid+1,pr,l,r);
}

}

void update(int u,int v) {
	w[u][1][0] += v - a[u];
	a[u] = v;
	matrix p,q;
	while(u) {
		p = sgt::query(1,1,n,id[top[u]],low[top[u]]);
		sgt::update(1,1,n,id[u]);
		q = sgt::query(1,1,n,id[top[u]],low[top[u]]);
		u = fa[top[u]];
		w[u][0][0] += max(q[0][0],q[1][0]) - max(p[0][0],p[1][0]);
		w[u][0][1] = w[u][0][0];
		w[u][1][0] += q[0][0] - p[0][0];
	}
}

signed main() {
	init();
	n = rd();m = rd();
	for(int i = 1;i<=n;i++)
		a[i] = 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);
	sgt::build(1,1,n);
	while(m--) {
		int x = rd(),y = rd();
		update(x,y);
		matrix ans = sgt::query(1,1,n,id[1],low[1]);
		wt(max(ans[0][0],ans[1][0]));
		putchar('\n');
	}
	return 0;
}

高斯消元

#include<bits/stdc++.h>
using namespace std;
const int N = 105;
const double Exp = 1e-12;
int n;
double a[N][N];
signed main() {
    scanf("%d",&n);
    for(int i = 1;i<=n;i++)
        for(int j = 1;j<=n + 1;j++)
            scanf("%lf",&a[i][j]);
    for(int i = 1;i<=n;i++){
        int mx = i;
        for(int j = i + 1;j<=n;j++)
            if(fabs(a[j][i]) > fabs(a[mx][i]))
                mx = j;
        if(mx != i)
            for(int j = 1;j<=n + 1;j++)
                swap(a[mx][j],a[i][j]);
        if(fabs(a[i][i]) < Exp) {
            puts("-1");
            return 0;
        }
        for(int j = 1;j<=n;j++) {
            if(j ^ i) {
                double p = a[j][i] / a[i][i];
                for(int k = 1;k<=n + 1;k++)
                    a[j][k] -= a[i][k] * p;
            }
        }
    }
    for(int i = 1;i<=n;i++) 
        printf("x%d=%.2lf\n",i,(fabs(a[i][n + 1] / a[i][i]) < Exp) ? 0:a[i][n + 1] / a[i][i]);
	return 0;
}

BSGS

#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);
}

int p,b,n,base;
map<int,int> m;

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;
}

bool bsgs(){
    int cur = 1;
    for(int i = 0;i<base;i++,cur = cur * b % p) {
        if(!m.count(cur)) m[cur] = i;
        if(cur == n) {
            printf("%lld",i);
            return true;
        }
    }
    for(int i = 1,now = 1;i <= base;i++) {
        now = now * cur % p;
        if(!now) continue;
        int key = qpow(now,p - 2) * n % p;
        if(m.count(key)) {
            printf("%lld",i * base + m[key]);
            return true;
        }
    }
    return false;
}

signed main() {

    p = rd(),b = rd(),n = rd();
    base = sqrt(p);
    if(!bsgs()) puts("no solution");

	return 0;
}

树Hash

#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);
}
#define ull unsigned long long
const int N = 1e6+10;
const ull mask = chrono::steady_clock::now().time_since_epoch().count();
ull shift(ull x) {
    x ^= mask;
    x ^= x << 13;
    x ^= x >> 7;
    x ^= x << 17;
    x ^= mask;
    return x;
}
ull Hash[N];
vector<int> edge[N];
set<ull> trees;
int n;
void getHash(int x,int fa) {
    Hash[x] = 1;
    for(int i : edge[x]) {
        if(i == fa) continue;
        getHash(i,x);
        Hash[x] += shift(Hash[i]);
    }
    trees.emplace(Hash[x]);
}

signed main() {

    n = rd();
    for(int i = 1;i<n;i++) {
        int u = rd(),v = rd();
        edge[u].emplace_back(v);
        edge[v].emplace_back(u);
    }
    getHash(1,0);
    wt(trees.size());
	return 0;
}

异或基

#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 = 55;
int n,k,a[N],ans;

void gauss() {
    for(int i = 62;i>=0;i--) {
        for(int j = k;j<n;j++) 
            if((a[j] >> i) & 1) {swap(a[k],a[j]);break;}
        if((a[k] >> i & 1) == 0) continue; 
        for(int j = 0;j<n;j++)
            if((a[j] >> i & 1) && j != k) 
                a[j] ^= a[k];
        k++;
        if(k == n) break;
    }
}

signed main() {

    n = rd();
    for(int i = 0;i<n;i++) a[i] = rd();
    gauss();
    for(int i = 0;i<k;i++) ans ^= a[i];
    wt(ans);

	return 0;
}

迪杰斯特拉

struct node{
    int x,d;
    node(int x,int d) : x(x),d(d){}
    friend bool operator < (node a,node b) {
        return a.d > b.d;
    }
};

int dis[N];
bool vis[N];
void dij() {
    memset(vis,0,sizeof(vis));
    memset(dis,0x3f,sizeof(dis));
    priority_queue<node> q;
    q.emplace(node(1,0));
    dis[1] = 0;
    while(q.size()) {
        node t = q.top();
        q.pop();
        if(vis[t.x]) continue;
        vis[t.x] = true;
        for(int i = g.head[t.x];~i;i = g.nxt[i]) {
            int y = g.to[i];
            if(dis[y] > dis[t.x] + g.val[i]) {
                dis[y] = dis[t.x] + g.val[i];
                q.emplace(node(y,dis[y]));
            }
        }
    }
}

EXGCD

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

CRT(China Remain Theory)

LL CRT(int k, LL *a, LL *r) {
    LL n = 1, ans = 0;

    for (int i = 1; i <= k; i++)
        n = n * r[i];

    for (int i = 1; i <= k; i++) {
        LL m = n / r[i], b, y;
        exgcd(m, r[i], b, y);  // b * m mod r[i] = 1
        ans = (ans + a[i] * m * b % n) % n;
    }

    return (ans % n + n) % n;
}

FFT

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

const int N = 4.2e6;
const double pi = acos(-1);
int n,r[N];
struct C {
    double r,i;
    C() {r = 0,i = 0;}
    C(double a,double b) {r = a,i = b;}
    friend C operator + (const C &a,const C &b) {return C(a.r + b.r,a.i - b.i);}
    friend C operator - (const C &a,const C &b) {return C(a.r - b.r,a.i - b.i);}
    friend C operator * (const C &a,const C &b) {
		return C(a.r * b.r - a.i * b.i,a.r * b.i + a.i  * b.r);
	}
    void operator += (const C &b) {r += b.r;i += b.i;}
    void operator *= (const C &b) {double t = r;r = r * b.r - i * b.i;i = t * b.i + i * b.r;}
}f[N],g[N];

void FFT(C *a,const int op) {
    C W,w,t,*a0,*a1;
    int i,j,k;
    for(int i = 0;i<n;i++)
        if(i < r[i])
            swap(a[i],a[r[i]]);
    for(int i = 1;i<n;i <<= 1) 
        for(W = C(cos(pi / i),sin(pi / i) * op),j = 0;j < n;j += i << 1) 
            for(w = C(1,0),a1 = i + (a0 = a + j),k = 0;k < i; ++k,++a0,++a1,w *= W)
                t = *a1*w,*a1 = *a0 - t,*a0 += t;
}
int m,l = 0;
signed main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr),cout.tie(nullptr);

    cin>>n>>m;
    for(int i = 0;i<=n;i++) cin>>f[i].r;
    for(int i = 0;i<=m;i++) cin>>g[i].r;
    for(m += n,n = 1;n <= m;n <<= 1,++l);
    for(int i = 0;i<n;i++) r[i] = (r[i >> 1] >> 1 | ((i & 1)<<(l - 1))); // rader 映射
    FFT(f,1);FFT(g,1); // DFT
    for(int i = 0;i<n;i++) f[i] *= g[i]; // 整合成 f * g 函数的FFT
    FFT(f,-1);// 做一遍IDFT还原
    for(int i = 0;i<=m;i++) printf("%.0lf ",fabs(f[i].r)/n);

	return 0;
}
;