模板整合计划 写了一点qwq慢慢补

板子整合计划

求查错\(qwq\)
不开\(long~long\)爆的连裤衩都没了

inline int read(){//快读 cctype iostream
	int x = 0; bool op = 0;char c = getchar();
	while(!isdigit(c))op |= (c == '-'), c = getchar();
	while(isdigit(c))x = (x << 1) + (x << 3) + (c ^ 48), c = getchar();
	return op ? -x : x;
}
inline int read(){
	int x = 0; bool op = 0;char c = getchar();
	while(c > '9' || c < '0')op |= (c == '-'), c = getchar();
	while(c>='0'&&c<='9')x = (x << 1) + (x << 3) + (c ^ 48), c = getchar();
	return op ? -x : x;
}

找树的直径 两遍\(dfs\)写法

dep[N] = {-1};
void dfs(int x,int fa){
    dep[x] = dep[fa] + 1;
    if(dep[x] > dep[maxx]) maxx = x;//获取最深节点
    for(int i = head[x];i;i = e[i].next){
        int v = e[i].to; if(v == fa) continue;
        dfs(v,x);
    }
}
main(){
    dfs(1,0); dfs(maxx,0);
    cout<<dep[maxx];
}

换根dp

void dp(int x){
    vis[x] = 1;
    for(int i = head[x];i;i = e[i].next){
        int v = e[i].to;
        if(vis[v]) continue; dp(y);
        ans = max(ans,dep[x]+dep[y]+e[i].w);
        dep[x] = max(dep[x],d[y] + e[i].w);
    }
}

kruskal最小生成树(最大把小于换大于)

struct edge_tu{int from,to,w;}e1[N<<1];
struct edge_tree{int from,to,w;}e2[N<<1];
void add(int u,int v,int w){
    e2[++tot] = (edge_tree){head[u],v,w}; head[u] = tot;
}
int find(int x){return x == fa[x] ? x : fa[x] = find(fa[x]);}
bool cmp(edge_tu a,edge_tu b){
    return a.w < b.w;
}
void kruskal(){
    sort(e1 + 1,e1 + m + 1,cmp);
    for(int i = 1;i <= m;++i){
    	int x = find(e1[i].x),y = find(e1[i]); 
        if(x == y) continue; fa[x] = y;
        add(e1[i].u.e1[i].v,e1[i].w);
        add(e1[i].v, e1[i].u, e1[i].w);
        if (++num == n) return;
    }
}

并查集

int find(int x){
	if(x == fa[x]) return x;//找到辈最大的
	return fa[x] = find(fa[x]);//递归写法,路径压缩,不停加辈,爷爷变成爸爸,保证以后询问的话只向上跳一次
}
inline int find(int x){
	while(fa[fa[x]] != fa[x]) fa[x] = fa[fa[x]];
	return fa[x];//循环写法,调动栈空间少且容易理解 
	//实际貌似又大了又慢了 
}
int main(){
	cin >> n >> m; int q,x,y;
	for(int i = 1;i <= n;++i) fa[i] = i;//初始爸爸是自己
	for(int i = 1;i <= m;++i){
		q = read(); x = read(); y = read();
		if(q & 1) fa[find(x)] = find(y);//统一爸爸
		else (find(x) == find(y)) ? puts("Y") : puts("N");//同一集合爸爸一样
	}
}

快速幂龟速乘

int qpow(int a,int b){
	int ans = 1;
	for(;b;b >>= 1){
		if(b & 1) ans = (long long)ans * a % mod;
		a = a * a % mod;
	}
	return ans;
}
ll mul(ll a,ll b){
	ll ans = 0;
	for(;b;b >>= 1){
		if(b & 1) ans = (ans + a) % mod;
		a = (a + a) % mod;
	}
	return ans;
}

\(a*b~mod~p=a*b-\lfloor a*b/p\rfloor*p\)

线段树 单点修改 区间乘 区间加 区间和

struct node{int v,add,mul;}tree[N<<2];
void pushdown(int root,int l,int r){//维护lazy 
	int mid = (l + r)>>1;//儿子的值*爸爸的mul+儿子的区间长度*爸爸的add 先求和,再lazy 
	tree[root<<1].v = (tree[root<<1].v * tree[root].mul + tree[root].add * (mid - l + 1))%p;
	tree[root<<1|1].v = (tree[root<<1|1].v*tree[root].mul+tree[root].add*(r - mid))%p;
	tree[root<<1].mul = (tree[root].mul * tree[root<<1].mul)%p;
	tree[root<<1|1].mul = (tree[root].mul * tree[root<<1|1].mul)%p;
	tree[root<<1].add = (tree[root].mul * tree[root<<1].add + tree[root].add)%p;
	tree[root<<1|1].add = (tree[root].mul * tree[root<<1|1].add + tree[root].add)%p;
	tree[root].mul = 1; tree[root].add = 0; return;
}
void change(int root,int l,int r,int x,int data){
	if(l == r) {
		tree[root].v = data; 
		tree[root].add = 0; tree[root].mul = 1; return;
	}
	pushdown(root,l,r);
	int mid = (l + r) >>1;
	if(x <= mid) change(root<<1,l,mid,x,data);
	else change(root<<1|1,mid+1,r,x,data);
	tree[root].v = (tree[root<<1].v + tree[root<<1|1].v) % p;
}
void build(int root,int l,int r){
	tree[root].mul = 1;
	tree[root].add = 0;
	if(l == r) tree[root].v = a[l];//
	else{
		int mid = (l + r)>>1;
		build(root<<1,l,mid); build(root<<1|1,mid +1,r);
		tree[root].v = tree[root<<1].v + tree[root<<1|1].v;
	}
	tree[root].v %= p;
	return;
}
void tmul(int root,int stdl,int stdr,int l,int r,int k){
	if(r < stdl || l > stdr) return;
	if(l <= stdl && r >= stdr){
		tree[root].v = (tree[root].v * k) % p;
		tree[root].mul = (tree[root].mul * k) % p;
		tree[root].add = (tree[root].add * k) % p;
		return;
	}
	pushdown(root,stdl,stdr);
	int mid = stdl + stdr >>1;
	tmul(root<<1,stdl,mid,l,r,k); tmul(root<<1|1,mid+1,stdr,l,r,k);
	tree[root].v = (tree[root<<1].v + tree[root<<1|1].v) % p;
	return;
}
void tadd(int root,int stdl,int stdr,int l,int r,int k){
	if(r < stdl || l > stdr) return;
	if(l <= stdl && r >= stdr){
		tree[root].add = (tree[root].add + k) % p;
		tree[root].v = (tree[root].v + k * (stdr - stdl + 1)) % p;
		return;
	}
	pushdown(root,stdl,stdr);
	int mid = stdl + stdr >> 1;
	tadd(root<<1,stdl,mid,l,r,k); tadd(root<<1|1,mid+1,stdr,l,r,k);
	tree[root].v = (tree[root<<1|1].v + tree[root<<1].v) % p;
	return;
}
int query(int root,int stdl,int stdr,int l,int r){
	if(r < stdl || l > stdr) return 0;
	if(l <= stdl && r >= stdr) return tree[root].v;
	pushdown(root,stdl,stdr);
	int mid = (stdl + stdr) >> 1;
	return (query(root<<1,stdl,mid,l,r) + query(root<<1|1,mid+1,stdr,l,r)) % p;
}

树状数组 单点+ 区间查询 逆序对 区间修改

inline int lowbit(int x){return x & (-x);}
void build(){
	for(int i = 1;i <= n;++i) cin >> a[i],sum[i] = sum[i-1] + a[i];
	for(int i = 1;i <= n;++i) tre[i] = sum[i] - sum[i - lowbit(i)];
	//每个树状数组i维护lowbit(i)的长度 
}//O(n)建树法,sum是前缀和
inline void add(int a,int b){
	for(;a <= n;a += lowbit(a)) c[a] += b;
}//单点修改
inline int ask(int i){
	int ans = 0;
	for(;i;i -= lowbit(i)) ans += c[i];
	return ans;
}
//逆序对
for(int i = n;i;--i){
    ans += ask(a[i]-1);
    add(a[i],1);
}
//区间修改
inline int query(int x){
		int ans = 0;
		for(int i = x;i;i -= lowbit(i))
		ans += (x + 1) * c1[i] - c2[i];
		return ans;
	}
	inline void add(int x,int a){
		for(int i = x;i <= n;i += lowbit(i)) c1[i] += a,c2[i] += x * a;
	}
main:
add(i,a[i]-a[i-1]);

\(RMQ - ST\)

\(f[i][j]\)表示从\(a[i]\)\(a[i+2^j-1]\)的最大值/最小值

\(f[i][j]\)分成\(f[i][j-1]\)\(f[i+2^{j-1}][j-1]\)

\(f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1])\)

边界\(f[i][0]=a[i]\)

log[0] = -1;
for(int i = 1;i <= n;++i) log[i] = log[i>>1] + 1;
for(int j = 1;j <= 20;++j)
    for(int i = 1;i+(1<<j)-1 <= n;++i)
        f[i][j] = max(f[i][j-1],f[i+(1<<(j-1))][j-1]);
//求区间[x,y]最大值
int k = log[y-x+1];
ans = max(f[x][k],f[y-(1<<k)+1][k])

离散化

memcpy(a,c,sizeof(c));
sort(a + 1,a + n + 1);
int siz = unique(a + 1,a + n + 1)- a - 1;
for(int i = 1;i <= n;++i) b[i] = lower_bound(a + 1,a + siz + 1,a[i])-a+1;

归并排序求逆序对

inline void q_merge(int l, int r) {
	if (l == r) return;
	int mid = l + r >> 1;
	q_merge(l, mid);
	q_merge(mid + 1, r);
	int i = l, j = mid + 1, k = l;
	while(i <= mid || j <= r) {
		if (j > r || i <= mid && a[i] <= a[j]) b[k ++] = a[i ++];
		else {
			b[k ++] = a[j ++];
			ans += mid - i + 1;
		} 
	}
	for (int i = l; i <= r; i ++) a[i] = b[i];
	return;
}

tarjan找割边 \(dfn[x]<low[y]\)

//tarjan找割边/桥
void tarjan(int x,int in_edge){
	dfn[x] = low[x] = ++num;
	for(int i = head[x];i;i = e[i].next){
		int v = e[i].to;
		if(!dfn[v]){
			tarjan(v,i);
			low[x] = min(low[x],low[y]);
			if(low[y] > dfn[x]) bridge[i] = bridge[i ^ 1] = 1;
		}
		else if(i != (in_edge ^ 1))
			low[x] = min(low[x],dfn[v]);
	}
}

割点判定\(dfn[x]\le low[y]\)

void tarjan(int x){
    dfn[x] = low[x] = ++num; int flag = 0;
    for(int i = head[x];i;i = e[i].next){
        int v = e[i].to;
        if(!dfn[y]){
            tarjan(y);
            low[x] = min(low[x],low[y]);
            if(low[y] >= dfn[x]){
                ++flag;
                if(x != root || flag > 1) cut[x] = true;
			}
        }
	}
}

树链剖分

void dfs1(int x,int f){
    dep[x] = dep[f] + 1; fa[x] = f; siz[x] = 1;
    for(int i = head[x];i;i = e[i].next){
        if(v == f) continue;
        dfs1(v,x);
        siz[x] += siz[v]; 
        if(siz[son[x]] < siz[v]) son[x] = v;
    }
}
void dfs2(int x,int tp){
    top[x] = tp;
    dfn[x] = ++cnt; rk[cnt] = x;
    if(son[x]) dfs2(son[x],tp);
    for(int i = head[x];i;i = e[i].next){
        int v = e[i].to;
        if(v == fa[x] || v == son[x]) continue;
        dfs2(v)
    }
}
//树剖求lca
int lca(int x,int y){
	int fx = top[x],fy = top[y];
	while(fx != fy){
		if(dep[fx] < dep[fy]) swap(x,y),swap(fx,fy);
		x = fa[top[x]]; fx = top[x];
	}
	return dep[x] > dep[y] ? y : x;
}

\(dijkstra\)板子 求到\(s\)的单源最短路径

priority_queue<pair<int,int> >q;
void dijkstra(){
	memset(d,0x3f,sizeof(d));
	d[s] = 0;
	q.push(make_pair(0,s));
	while(q.size()){
		int x = q.top().second; q.pop();
		if(v[x]) continue;
		v[x] = 1;
		for(int i = head[x];i;i = e[i].next){
			int y = e[i].to,z = e[i].w;
			if(d[y] > d[x] + z){
				d[y] = d[x] + z;
				q.push(make_pair(-d[y],y));
			}
		}
	}
}

\(spfa\)

void spfa(){
	memset(d,0x3f,sizeof(d));
	d[s] = 0; queue<int> q;
	q.push(s); vis[s] = 1;
	while(q.size()){
		int x = q.front(); q.pop();
		vis[x] = 0;
		for(int i = head[x];i;i = e[i].next){
			int v = e[i].to,z = e[i].w;
			if(d[v] > d[x] + z){
				d[v] = d[x] + z;
				if(!vis[v]) q.push(v),vis[v] = 1;
			}
		}
	}
}

\(floyed\)传递闭包/距离 \(bitset\)优化

bitset<N>f[N];
for(int k = 1;k <= n;++k)
    for(int i = 1;i <= n;++i)
        for(int j = 1;j <= n;++j)
            f[i][j] |= f[i][k] & f[k][j];
			//f[i][j] = min(f[i][j],min(f[i][k],f[k][j]));

倍增$LCA $ \(dfs\)中顺便处理\(LCA\)

void dfs1(int u,int f){
    dep[u] = dep[f] + 1; fa[u][0] = f;
    for(int j = 1;j <= 20;++j) fa[u][j] = fa[u][fa[u][j-1]];
    for(int i = head[u];i;i = e[i].next){
        int v = e[i].to; if(v == f) continue;
        dfs1(v,u);
    }
}
inline int lca(int x,int y){
    if(dep[x] < dep[y]) swap(x,y);
    for(int i = 20;i >= 0;--i){
        if(dep[fa[x][i]] >= dep[y]) x = fa[x][i];
        if(x == y) return x;
    }
    for(int i = 20;i >= 0;--i){
        if(fa[x][i] != fa[y][i]){
            x = fa[x][i];
            y = fa[y][i];
		}
	}
    return fa[x][0];
}

树上差分

int dfs2(int x,int f){
	for(int i = head[x];i;i = e[i].next){
		int v = e[i].to;
		if(v == f) continue;
		dfs2(v,x);
		cha[x] += cha[v];
	}
}
for(int i = 1;i <= k;++i){
		u = read(); v = read();
		++cha[u]; ++cha[v]; cha[lca(u,v)] -= 2;//边差分
	}
for(int i = 1;i <= k;++i){
    u = read(); v = read(); int z = lca(u,v);
    ++cha[u]; ++cha[v]; --cha[z]; --cha[fa[z]];//点差分
}

已知中后序遍历,求先序遍历

inline int find(char ch){
    for(int i = 0;i < len;++i)
        if(s1[i] == ch) return i;
}
void dfs(int l1,int r1,int l2,int r2){
    int m = find(s2[r2]);
    cout << s2[r2];
    if(m > l1) dfs(l1,m - 1,l2,r2 - r1 + m - 1);
    if(m < r1) dfs(m + 1,r1,l2 + m -l1.r2 -1);
}

板子整合计划2

杂项 $ :C_nm=C_{n-1}+C_{n-m}^m$ \(vector的end\)是越界的

整体集合上的二分

while(l <= r){
    int mid = l + r >>1;
    if(...) r = mid - 1;
    else r = mid + 1;
}

\(e-DCC\)

void dfs(int x){
	c[x] = dcc;
	for(int i = head[x];i;i = e[i].next){
		int v = e[i].to;
		if(c[v] || bridge[i]) continue;
		dfs(v);
	}
}
main(){
	for(int i = 1;i <= n;++i)
		if(!c[i]){
			++dcc;
			dfs(i);
		}
	//dcc:有几个  c[i]:i belong to which gcc
    //还得用tarjan找桥
}

链表

struct node{
	int val,prev,next;
}node[size];
int head,tail,tot;
int init(){
	tot = 2;
	head = 1;tail = 2;
	node[head].next = tail;
	node[tail].prev = head;
}
int insert(int p,int val){
	q = ++tot;
	node[q].val = val;
	node[node[p].next].prev = q;
	node[p].next = q;
	node[q].next = p;
}
void remove(int p){
	node[node[p].prev].next = node[p].next;
	node[node[p].next] = node[p].prev;
}
void clear(){
	memset(node,0,sizeof(node));
	head = tail = tot = 0;
}

\(O(nloglogn)\)埃氏筛

void primes(int n){
    memser(vis,0,sizeof(vis));
    for(int i = 2;i <= n;++i){
        if(vis[v]) continue;
        printf("%d",i); //i是质数
        for(int j = i;j <= n/i;++j) vis[i * j] = 1;
	}
}

\(O(n)\)线性筛

void primes(int n){
    memset(vis,0,sizeof(vis));
    num = 0;//素数数量
    for(int i = 2;i <= n;++i){
        if(!vis[i]) vis[i] = prime[++num] = i;
        for(int j = 1;j <= num;++j){
            //i有比prime[j]更小的质因子,或者超过n的范围,break
            if(prime[j] > vis[j] || prime[j] > n/i) break;
            vis[i * prime[j]] = prime[j];
        }
	}
}

\(exgcd\)

\(ax+by=c\) \(gcd(a,b)|c\)有解,通解为\(x=\frac cdx_0+\frac bdt,y=\frac cdy_0-\frac adt,t\in z,d=gcd(a,b)\)

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

欧拉筛phi

int v[N],phi[N],prime[N];
void euler(int n){
    memset(vis,0,sizeof(vis));
    num = 0;//质数
    for(int i = 2;i <= n;++i){
        if(!vis[i]){
            vis[i] = prime[++num]= i;
            phi[i] = i-1;
        }
    	for(int j = 1;j <= num;++j){
        	if(prime[j] > vis[i] || prime[j] > n/i) break;
            vis[i * prime[j]] = prime[j];
            phi[i * prime[j]] = phi[j];
            vis[i * prime[j]] = 
                phi[i] * (i % prime[j] ? prime[j] - 1 : prime[j]);
    	}
    }
}

phi

int phi(int n){
    int ans = n; int az = sqrt(n);
    for(int i = 2;i <= az;++i)
        if(n % i == 0)[
            ans = ans/ i * (i-1);
            while(n % i == 0) n /= i;
        ]
    if(n > 1) ans = ans / n * (n-1);
}

线性求逆元

for (int i = 2;i <= n;++i){                
    	inv[i] = -mod/i * inv[mod%i] % mod;
		inv[i] = (inv[i] + mod) % mod;
}

\(O(n)\)\(k\)

int find(int l,int r) {
    if(l == r && l == k) return a[k];
    if(l < r) {
        int i = l,j = r;
        int tmp = a[l];
        while(i < j) {
            while(i < j &&a[j] >= tmp) --j;
            if(i < j) swap(a[i],a[j]);
            while(i < j && a[i] <= tmp) ++i;
            if(i < j) swap(a[i],a[j]);
        }
        a[i] = tmp;
        if(i == k) return a[k];
        if(i > k) return find(l,i - 1);
        else return find(i + 1,r);
    }
}
posted @ 2020-08-26 15:06  INFP  阅读(266)  评论(2编辑  收藏  举报