【板子】数据结构 && 图论 && 数论

更新

2021-05-10 加入split

2020-12-13 加入技巧章节

2020-06-27 加入Kosaraju

2020-06-26 加入前向星、二分、修复割顶

2020-06-25 加入Trie树、O2优化、万能头部、二进制拆分、拓扑排序

2020-06-25 加入最小生成树、KMP、Dijkstra。更新矩阵快速幂

2020-06-25 更新代码片段,调整文档结构

2020-06-25 重新排版

2017-11-09 NOIP第一次整理上传

前言

自用板子,经测试代码均正确,可以放心食用,源自于17年准备NOIP(当时还不会md😭)。大学程序设计课对板子进行完善。

代码片段

// #pragma GCC optimize(2) 
// #include<bits/stdc++.h>
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <functional>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <string>
#include <vector>
#define LL long long
using namespace std;
inline int get_num() {
    char c;
    int f = 1, num = 0;
    while ((c = getchar()) == ' ' || c == '\n' || c == '\r')
        ;
    if (c == '-')
        f = -1;
    else
        num = c - '0';
    while (isdigit(c = getchar())) num = num * 10 + c - '0';
    return num * f;
}
int main() {
    // ios::sync_with_stdio(false);
    // cout.tie(NULL);
    freopen("a.in", "r", stdin);
    freopen("a.out", "w", stdout);

    fclose(stdin);
    fclose(stdout);
    return 0;
}

数据结构

线段树

inline void push_up(int p){
	tr[p].w=tr[p<<1].w+tr[p<<1|1].w;
}
inline void push_down(int p){
	if(!tr[p].lazy) return ;
	tr[p<<1].w+=tr[p].lazy*(tr[p<<1].r-tr[p<<1].l+1);
	tr[p<<1].lazy+=tr[p].lazy;
	tr[p<<1|1].w+=tr[p].lazy*(tr[p<<1|1].r-tr[p<<1|1].l+1);
	tr[p<<1|1].lazy+=tr[p].lazy;
	tr[p].lazy=0;
}
void build(int p,int l,int r){
	tr[p].l=l;tr[p].r=r;
	if(l==r){
		tr[p].w=get_num();
		return ;
	}
	int mid=(l+r)>>1;
	build(p<<1,l,mid);build(p<<1|1,mid+1,r);
	push_up(p);
}
void add(int p,int l,int r,LL k){
	if(tr[p].l==l&&tr[p].r==r){
		tr[p].w+=(r-l+1)*k;
		tr[p].lazy+=k;
		return ;
	}
	push_down(p);
	int mid=(tr[p].r+tr[p].l)>>1;
	if(r<=mid) add(p<<1,l,r,k);
	else if(l>mid) add(p<<1|1,l,r,k);
	else{
		add(p<<1,l,mid,k);add(p<<1|1,mid+1,r,k);
	}
	push_up(p);
	
}
LL query(int p,int l,int r){
	if(tr[p].l==l&&tr[p].r==r){
		return tr[p].w;
	}
	LL ans=0;
	push_down(p);
	int mid=(tr[p].r+tr[p].l)>>1;
	if(r<=mid) ans=query(p<<1,l,r);
	else if(l>mid) ans=query(p<<1|1,l,r);
	else{
		ans=query(p<<1,l,mid)+query(p<<1|1,mid+1,r);
	}
	push_up(p);
	return ans;
	
}
int main()
{
	int n,m;n=get_num();m=get_num();
	build(1,1,n);
	int c,x,y;LL k;
	for(int i=1;i<=m;i++){
		c=get_num();x=get_num();y=get_num();
		if(c==1){
			k=get_num();
			add(1,x,y,k);
		}else{
			cout<<query(1,x,y)<<'\n';
		}
	}
	return 0;
}

树链剖分

inline void push_up(int p){
	tr[p].w=tr[p<<1].w+tr[p<<1|1].w;
}
inline void push_down(int p){
	if(!tr[p].lazy) return ;
	tr[p<<1].w+=tr[p].lazy*(tr[p<<1].r-tr[p<<1].l+1);
	tr[p<<1].lazy+=tr[p].lazy;
	tr[p<<1|1].w+=tr[p].lazy*(tr[p<<1|1].r-tr[p<<1|1].l+1);
	tr[p<<1|1].lazy+=tr[p].lazy;
	tr[p].lazy=0;
}
void build(int p,int l,int r){
	tr[p].l=l;tr[p].r=r;
	if(l==r){
		tr[p].w=w[l];
		return ;
	}
	int mid=(l+r)>>1;
	build(p<<1,l,mid);
	build(p<<1|1,mid+1,r);
	push_up(p);
}
void add(int p,int l,int r,LL k){
	if(tr[p].l==l&&tr[p].r==r)
	{
		tr[p].w+=(r-l+1)*k;
		tr[p].lazy+=k;
		return ;
	}
	push_down(p);
	int mid=(tr[p].l+tr[p].r)>>1;
	if(r<=mid) add(p<<1,l,r,k);
	else if(l>mid) add(p<<1|1,l,r,k);
	else{
		add(p<<1,l,mid,k);add(p<<1|1,mid+1,r,k);
	}
	push_up(p);
}
LL query(int p,int l,int r){
	if(tr[p].l==l&&tr[p].r==r)
	{
		return tr[p].w;
	}
	LL ans=0;
	push_down(p);
	int mid=(tr[p].l+tr[p].r)>>1;
	if(r<=mid) ans=query(p<<1,l,r);
	else if(l>mid) ans=query(p<<1|1,l,r);
	else{
		ans=query(p<<1,l,mid)+query(p<<1|1,mid+1,r);
	}
	push_up(p);
	return ans;
}
void dfs_1(int x){
	siz[x]=1;
	for(int i=0;i<v[x].size();i++){
		if(cur!=f[x]){
			f[cur]=x;
			deep[cur]=deep[x]+1;
			dfs_1(cur);
			siz[x]+=siz[cur];
			if(siz[son[x]]<siz[cur]) son[x]=cur;
		}
	}
}
void dfs_2(int x,int p){
	id[x]=++tot;w[tot]=d[x];top[x]=p;
	if(son[x]) dfs_2(son[x],p);
	for(int i=0;i<v[x].size();i++){
		if(cur!=f[x]&&cur!=son[x]){
			dfs_2(cur,cur);
		}
	}
}
void modify(int a,int b,int k){
	while(top[a]!=top[b]){
		if(deep[top[a]]>deep[top[b]]) swap(a,b);
		add(1,id[top[b]],id[b],k);
		b=f[top[b]];
	}if(deep[a]>deep[b]) swap(a,b);
	add(1,id[a],id[b],k);
}
LL find(int a,int b){
	LL ans=0;
	while(top[a]!=top[b]){
		if(deep[top[a]]>deep[top[b]]) swap(a,b);
		ans+=query(1,id[top[b]],id[b]); ans%=MOD;
		b=f[top[b]];
	}if(deep[a]>deep[b]) swap(a,b);
	ans+=query(1,id[a],id[b]);
	return ans%MOD;
}
int main()
{
	int n,m,root;
	n=get_num();m=get_num();root=get_num();MOD=get_num();
	for(int i=1;i<=n;i++) d[i]=get_num();
	for(int i=1;i<n;i++){
		int a,b;
		a=get_num();b=get_num();v[a].push_back(b);
		v[b].push_back(a);
	}
	dfs_1(root);
	dfs_2(root,root);
	build(1,1,n);
	int c,x,y;LL z;
	for(int i=1;i<=m;i++){
		c=get_num();x=get_num();
		if(c==1){
			y=get_num();
			z=get_num();
			modify(x,y,z%MOD);
		}else if(c==2)
		{
			y=get_num();
			cout<<find(x,y)<<'\n';
		}else if(c==3){
			z=get_num();
			add(1,id[x],id[x]+siz[x]-1,z%MOD);
		}else if(c==4){
			cout<<query(1,id[x],id[x]+siz[x]-1)%MOD<<'\n';
		}
	}
	return 0;
}

并查集

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

初始化 for(int i=1;i<=n;i++) f[i]=i;

树状数组 1

在全局有个 n n n,主函数有个 n n n,读入 n n n的时候,全局相当于 n n n是0。

树状数组 2

void modify(int x,LL p){
	for(int i=x;i<=n;i+=lowbit(i)) tr[i]+=p;
	//for和tr的i不要写错啊
}
LL query(int x){
	LL ans=0;
	for(int i=x;i;i-=lowbit(i)) ans+=tr[i];
	return ans;
}
  • modify(x,k);modify(y+1,-k); 写的 modify(x,k);modify(y+1,k);

  • for(int i=x;i<=n;i+=lowbit(i)) tr[i]+=p; 写的 for(int i=x;i<=n;i+=lowbit(i)) tr[x]+=p;

STL堆,priority_queue

priority_queue<int,vector<int>,greater<int> >Q;
	int n;n=get_num();
	int c,x;
	for(int i=1;i<=n;i++){
		c=get_num();
		if(c==1){
			x=get_num();
			Q.push(x);
		}else if(c==2){
			cout<<Q.top()<<'\n';
		}else {
			Q.pop();
		}
	}

前向星

inline void add(int x,int y,int w){
	v[++p].to=y;
	v[p].nxt=fa[x];
	v[p].w=w;
	fa[x]=p;
}

好久没用了,记一下吧

图论

最近公共祖先

最近公共祖先(LCA)

void dfs(int x){
	vis[x]=1;
	for(int b=fa[x];b;b=v[b].nxt){
		if(!vis[cur])
		{
			deep[cur]=deep[x]+1;
			lca[cur][0]=x;
			dfs(cur);
		}
	}
}
int query(int a,int b)
{
	if(deep[a]>deep[b]) swap(a,b);
	for(int i=19;i>=0;i--) if(deep[lca[b][i]]>=deep[a]) b=lca[b][i];
	if(a==b) return a;
	for(int i=19;i>=0;i--){// 是大于等于0不是(int i=19;i;i--)
		if(lca[a][i]!=lca[b][i]){
			a=lca[a][i];b=lca[b][i];
		}
	}
	return lca[a][0];
}
	deep[s]=1;
	dfs(s);
	for(int j=1;j<=19;j++){
		for(int i=1;i<=n;i++){
			lca[i][j]=lca[lca[i][j-1]][j-1];
		}
	}

vector TLE 了俩点 还是好好用struct

最近公共祖先(Tarjan)

void tarjan(int x){
	vis[x]=1;
	f[x]=x;
	for(int b=fa[x];b;b=v[b].nxt){
		if(!vis[cur]){
			tarjan(cur);
			f[find(cur)]=x;
		}
	}
	for(int b=faa[x];b;b=qv[b].nxt){
		if(vis[qv[b].to]){
			qv[b^1].ans=qv[b].ans=find(qv[b].to);
		}
	}
}
void add(int x,int y){
	v[++p].to=y;
	v[p].nxt=fa[x];
	fa[x]=p;
}

v[++p].to=y;y写成了x

最近公共祖先(树剖)

void dfs_1(int x){
	siz[x]=1;
	for(int b=fa[x];b;b=v[b].nxt){
		if(cur!=f[x]){
			f[cur]=x;
			deep[cur]=deep[x]+1;
			dfs_1(cur);
			siz[x]+=siz[cur];//忘写了一开始
			if(siz[son[x]]<siz[cur]) son[x]=cur;
		}
	}
}
void dfs_2(int x,int p){
	top[x]=p;
	if(son[x]) dfs_2(son[x],p);
	for(int b=fa[x];b;b=v[b].nxt){
		if(cur!=f[x]&&cur!=son[x]){
			dfs_2(cur,cur);
		}
	}
}
int query(int a,int b){
	while(top[a]!=top[b]){
		if(deep[top[a]]>deep[top[b]]) swap(a,b);
		b=f[top[b]];
	}
	return (deep[a]<=deep[b])? a : b;
}

dfs_1的时候
dfs_1(cur)
忘记写:siz[x]+=siz[cur];
就相当于没有长长的链链了
就跳的很慢很慢了 然后就T了
其实常数是比LCA小的 OK的说

单源最短路径

SPFA

	int n,m,s;n=get_num();m=get_num();s=get_num();	for(int i=1;i<=m;i++){		int a,b,c;		a=get_num();b=get_num();c=get_num();		add(a,b,c);//注意单项边还是双向边	}	for(int i=1;i<=n;i++) d[i]=2147483647;	d[s]=0;	vis[s]=1;//忘写了一开始	Q.push(s);	while(!Q.empty()){		int h=Q.front();		vis[h]=0;		Q.pop();		for(int b=fa[h];b;b=v[b].nxt)		{			if(d[cur]>d[h]+v[b].w)			{				d[cur]=d[h]+v[b].w;				if(!vis[cur])				{					vis[cur]=1;					Q.push(cur);				}			}		}	}

queuevis[h]进来的时候 没有写vis[h]=0;

Floyd

	int n;n=get_num();	for(int i=1;i<=n;i++){		for(int j=1;j<=n;j++){			v[i][j]=get_num();		}	}for(int i=0;i<=n;i++) v[i][i]=0;	for(int k=1;k<=n;k++){		for(int i=1;i<=n;i++){			for(int j=1;j<=n;j++){				v[i][j]=min(v[i][j],v[i][k]+v[k][j]);			}		}	}	int m=get_num();	for(int i=1;i<=m;i++){		int a,b;a=get_num();b=get_num();		cout<<v[a][b]<<'\n';	}

Dijkstra

int main() {    int n;    n = get_num();    for (int i = 1; i <= n; i++) {        v[0][i] = v[i][0] = get_num();    }    for (int i = 1; i <= n; i++) {        for (int j = 1; j <= n; j++) {            v[i][j] = get_num();        }    }    for (int i = 0; i <= n; i++) {        vis[i] = 0;        d[i] = 1e9;    }    d[0] = 0;    int ans = 0;    for (int i = 0; i <= n; i++) {        int sum = 1e9, k;        for (int i = 0; i <= n; i++) {            if (!vis[i] && d[i] < sum) {                sum = d[i];                k = i;            }        }        ans += d[k];        vis[k] = 1;        for (int i = 0; i <= n; i++) {            d[i] = min(d[i], d[k] + v[k][i]);        }    }    cout << ans;    return 0;}

堆优化Dijkstra

struct re{
	int d,k;
};
struct cmp{
	inline bool operator () (re a, re b){
		return a.d>b.d;
	}
}; 
priority_queue<re,vector<re>,cmp >Q;
int main()
{
	int n,m;
	re s;
	n=get_num();m=get_num();s.k=get_num();
	for(int i=1;i<=m;i++){
		int a,b,c;a=get_num();b=get_num();c=get_num();
		add(a,b,c);
	}
	for(int i=1;i<=n;i++) d[i]=2147483647;
	d[s.k]=0;re B;s.d=0;
	Q.push(s);
	while(!Q.empty()){
		re h=Q.top();
		Q.pop();
		if(vis[h.k]) continue;
		vis[h.k]=1;
		for(int b=fa[h.k];b;b=v[b].nxt){
			if(d[cur]>d[h.k]+v[b].w){
				d[cur]=d[h.k]+v[b].w;
				B.d=d[cur];B.k=v[b].to;
				Q.push(B);
			}
		}
	}
	for(int i=1;i<=n;i++) cout<<d[i]<<" ";
	return 0;
}

负环

void dfs(int x){
	if(ans) return ;
	vis[x]=1;
	for(int b=fa[x];b;b=v[b].nxt){
		if(d[cur]>d[x]+v[b].w){
			d[cur]=d[x]+v[b].w;
			if(vis[cur])
			{
				ans=1;
				break;
			}
			dfs(cur);
		}
	}
	vis[x]=0;
}
	while(t)
	{
		t--;int n,m;
		memset(vis,0,sizeof(vis));
		memset(d,0,sizeof(d));
		memset(fa,0,sizeof(fa));p=0;
		n=get_num();m=get_num();
		for(int i=1;i<=m;i++){
			int a,b,w;
			a=get_num();b=get_num();w=get_num();
			add(a,b,w);
			if(w>=0) add(b,a,w); 
		}
		ans=0;
		for(int i=1;i<=n;i++){
			dfs(i);
			if(ans) break;
		}
		if(ans) cout<<"YE5\n";
		else cout<<"N0\n";
	}

最小生成树

Kruskal

const int MAXN = 3e2 + 7;int par[MAXN];struct re {    int x, y, w;    bool operator<(const re& a) const { return w < a.w; }} v[MAXN * MAXN];int find(int x) { return par[x] == x ? x : par[x] = find(par[x]); }int main() {    int n;    cin >> n;    int cnt = 1;    for (int i = 1; i <= n; i++) {        v[cnt].x = 0;        v[cnt].y = i;        cin >> v[cnt].w;        ++cnt;    }    for (int i = 1; i <= n; i++) {        for (int j = 1; j <= n; j++) {            int w = get_num();            if (i == j) continue;            v[cnt].x = i;            v[cnt].y = j;            v[cnt].w = w;            cnt++;        }    }    sort(v + 1, v + cnt);    int ans = 0, sum = 0;    for (int i = 1; i <= n; i++) par[i] = i;    for (int i = 1; i < cnt; i++) {        if (sum == n) break;        if (find(v[i].x) != find(v[i].y)) {            ans += v[i].w;            par[find(v[i].x)] = find(v[i].y);            sum++;        }    }    cout << ans;    return 0;}

Prim

const int MAXN = 3e2 + 7;int v[MAXN][MAXN], vis[MAXN], d[MAXN];int main() {    int n;    n = get_num();    for (int i = 1; i <= n; i++) {        v[0][i] = v[i][0] = get_num();    }    for (int i = 1; i <= n; i++) {        for (int j = 1; j <= n; j++) {            v[i][j] = get_num();        }    }    for (int i = 0; i <= n; i++) {        vis[i] = 0;        d[i] = 1e9;    }    d[0] = 0;    int ans = 0;    for (int i = 0; i <= n; i++) {        int sum = 1e9, k;        for (int i = 0; i <= n; i++) {            if (!vis[i] && d[i] < sum) {                sum = d[i];                k = i;            }        }        ans += d[k];        vis[k] = 1;        for (int i = 0; i <= n; i++) {            d[i] = min(d[i], v[k][i]);        }    }    cout << ans;    return 0;}

堆优化的Prim

const int MAXN = 3e2 + 7;int v[MAXN][MAXN], vis[MAXN], d[MAXN];struct re {    int d, w;    bool operator<(const re &a) const { return w > a.w; }};priority_queue<re> Q;int main() {    int n;    n = get_num();    for (int i = 1; i <= n; i++) {        v[0][i] = v[i][0] = get_num();    }    for (int i = 1; i <= n; i++) {        for (int j = 1; j <= n; j++) {            v[i][j] = get_num();        }    }    for (int i = 0; i <= n; i++) {        vis[i] = 0;        d[i] = 1e9;    }    d[0] = 0;    Q.push({0, 0});    int ans = 0;    while (!Q.empty()) {        re h = Q.top();        Q.pop();        if (vis[h.d]) continue;        vis[h.d] = 1;        ans += h.w;        for (int i = 0; i <= n; i++) {            if (d[i] > v[h.d][i]) {                d[i] = v[h.d][i];                Q.push({i, d[i]});            }        }    }    cout << ans;    return 0;}

二分图匹配 再打一遍

int dfs(int x){	for(int i=0;i<v[x].size();i++){		if(!vis[cur])		{			vis[cur]=1;			if(!match[cur]||dfs(match[cur]))			{				match[cur]=x;				match[x]=cur;				return 1;			}		}	}	return 0;}int n;int query(){	int ans=0;	for(int i=1;i<=n;i++){		if(!match[i]){			memset(vis,0,sizeof(vis));			if(dfs(i)) ans++;		}	}	return ans;}int main(){	int m,e;n=get_num();m=get_num();e=get_num();	for(int i=1;i<=e;i++){		int a,b;a=get_num();b=get_num();		if(b<=m) v[a].push_back(b+n);	}	cout<<query();	return 0;}

强连通分量

缩点 再打一遍

void tarjan(int x){	my_s.push(x);in_s[x]=1;//注意不要忘了	dfn[x]=low[x]=++tot;	for(int b=fa[x];b;b=v[b].nxt){		if(!dfn[cur]){			tarjan(cur);			low[x]=min(low[x],low[cur]);		} else if(in_s[cur]) low[x]=min(low[x],dfn[cur]);	}	if(low[x]==dfn[x])	{		++bcnt;		while(my_s.top()!=x){			fd[my_s.top()]=bcnt;d[bcnt]+=w[my_s.top()];in_s[my_s.top()]=0;my_s.pop();		}		d[bcnt]+=w[my_s.top()];fd[my_s.top()]=bcnt;in_s[my_s.top()]=0;my_s.pop();	}}void build(){	for(int i=1;i<=n;i++){		for(int b=fa[i];b;b=v[b].nxt)		{			if(fd[i]!=fd[cur])			{				qv[fd[i]].push_back(fd[cur]);			}		}	}}int dfs(int x){	if(dp[x]) return dp[x];	for(int i=0;i<qv[x].size();i++){		dp[x]=max(dp[x],dfs(qv[x][i]));	}	dp[x]+=d[x];	return dp[x];}

割顶(割点)

void tarjan(int x){	dfn[x]=low[x]=++tot;	int rt=0;	for(int b=fa[x];b;b=v[b].nxt){		if(!dfn[cur]){			rt++;			f[cur]=f[x];			tarjan(cur);			low[x]=min(low[x],low[cur]);			if(low[cur]>=dfn[x]&&f[x]!=x&&!vis[x]) vis[x]=1,ans++; //重要		}else  low[x]=min(low[x],dfn[cur]);	}	if(f[x]==x&&rt>=2) ans++,vis[x]=1;}

Kosaraju

int n, c[N], dfn[N], vis[N], dcnt, scnt;
vector<int> G1[N], G2[N];  // G1 原图,G2 反向图
void dfs1(int x) {
    vis[x] = 1;
    for (auto y : G1[x]) {
        if (!vis[y]) dfs1(y);
    }
    dfn[++dcnt] = x;
}
void dfs2(int x) {
    c[x] = scnt;
    for (auto y : G2[x]) {
        if (!c[y]) dfs2(y);
    }
}
void kosaraju() {
    dcnt = scnt = 0;
    memset(c, 0, sizeof(c));
    memset(vis, 0, sizeof(vis));
    for (int i = 1; i <= n; i++) {
        if (!vis[i]) dfs1(i);
    }
    for (int i = n; i >= 1; i--) {
        if (!c[dfn[i]]) ++scnt, dfs2(dfs[i]);
    }
}
  • 前序序列
  • 后序序列
  • 逆逆序序列(后序序列的逆序,原图缩点后的的拓扑顺序)

拓扑排序

bool topoSort(int n) {    queue<int> Q;    for (int i = 0; i < n; i++) {        if (in_deg[i] == 0) Q.push(i);    }    vector<int> ans;    while (!Q.empty()) {        int u = Q.front();        Q.pop();        ans.push_back(u);        for (auto& i : v[u]) {            if (--in_deg[i] == 0) Q.push(i);        }    }    if (ans.size() == n) {        for (auto& i : ans) {            cout << i << " ";        }        cout << endl;    } else        return false;}

树上差分

LL fast_pow(LL a,LL p,LL k){	LL ans=(a==0)?0:1;	a%=k;	for(;p;p>>=1,a=(a*a)%k)	{		if(p&1) ans=(ans*a)%k;	}return ans;}int main(){	LL n,l,r;cin>>n>>l>>r;	for(int i=1;i<=n;i++){		v[i].m=get_num();v[i].a=get_num();	}	LL M=1;	for(int i=1;i<=n;i++) M*=v[i].m;	for(int i=1;i<=n;i++){		v[i].M=M/v[i].m;		v[i].k=fast_pow(v[i].M,v[i].m-2,v[i].m);	}	LL ans=0;	for(int i=1;i<=n;i++) ans=(ans+v[i].a*v[i].M*v[i].k)%M;	//cout<<ans;	LL anss=0;	if(r>=ans) anss=(r-ans)/M+1;	if(l-1>=ans) anss-=(l-ans-1)/M+1;	if(anss==0) cout<<0<<'\n'<<0;	else{		cout<<anss<<'\n';		if(l-1>=ans){			cout<<((l-1-ans)/M+1)*M+ans;		}else cout<<ans;	}	return 0;}

最大流量

const int maxn=50010;struct re{	int fd,to,nxt,ans;}qv[maxn<<2];vector<int> v[maxn];int p=1,fa[maxn],vis[maxn],d[maxn],f[maxn],fath[maxn];int n,k;inline void add(int x,int y){	qv[++p].to=y;	qv[p].nxt=fa[x];	qv[p].fd=x;	fa[x]=p;}inline int get_num(){	char c;	int f=1,num=0;	while((c=getchar())==' '||c=='\n'||c=='\r');	if(c=='-') f=-1;	else num=c-'0';	while(isdigit(c=getchar())) num=num*10+c-'0';	return num*f;}int find(int x){	if(f[x]==x) return x;	return f[x]=find(f[x]);}void tarjan(int x){	vis[x]=1;	f[x]=x;	for(int i=0;i<v[x].size();i++){		if(!vis[cur]){			fath[cur]=x;			tarjan(cur);			f[find(cur)]=x;		}	}	for(int b=fa[x];b;b=qv[b].nxt){		if(vis[qv[b].to]){			qv[b].ans=qv[b^1].ans=find(qv[b].to);		}	}}void dfs(int x){	vis[x]=1;	for(int i=0;i<v[x].size();i++){		if(!vis[cur]){			dfs(cur);			d[x]+=d[cur]; 		}	}}int query(){	for(int i=2;i<=p;i+=2){		++d[qv[i].fd];++d[qv[i].to];--d[qv[i].ans];		--d[fath[qv[i].ans]];	}	memset(vis,0,sizeof(vis));	dfs(1);	int ans=0;	for(int i=1;i<=n;i++){		ans=max(ans,d[i]);	}return ans;}int main(){	n=get_num();k=get_num();	for(int i=1;i<n;i++){		int a,b;a=get_num();b=get_num();		v[a].push_back(b);v[b].push_back(a);	}	for(int i=1;i<=k;i++){		int a,b;a=get_num();b=get_num();		add(a,b);add(b,a);	}	for(int i=1;i<=n;i++){		if(!vis[i]) tarjan(i);	}	cout<<query();	return 0;}

算法

二分法

int find(int x) {
    int l = 1, r = n, ans = -1;
    while (l <= r) {
        int mid = (l + r) >> 1;
        if (a[mid] >= x) {
            ans = mid;
            r = mid - 1;
        } else
            l = mid + 1;
    }
    return ans;
}
int find(int x) {
    int l = 1, r = n;
    while (l <= r) {
        int mid = (l + r) >> 1;
        if (a[mid] >= x) {
            r = mid - 1;
        } else
            l = mid + 1;
    }
    return l;
}

三分法

int n;
double v[20];
double eps = 1e-7;
double find(double x) {  //find类型不要写错
    double ans = v[n + 1];
    double p = 1;
    for (int i = n; i; i--) {
        p *= x;
        ans += v[i] * p;
    }
    return ans;
}
int main() {
    double l, r, mid, midd;
    cin >> n >> l >> r;
    for (int i = 1; i <= n + 1; i++) cin >> v[i];
    while (l + eps <= r) {
        mid = (l + r) / 2;
        midd = (l + mid) / 2;
        if (find(midd) < find(mid))
            l = midd;
        else
            r = mid;
    }
    printf("%.5lf", l);
    return 0;
}

double 类型用的get_num()读进去了
其实应该用cin>>
能过样例也是奇迹

LCS(最长公共子序列) O ( n l o g n ) O(nlogn) O(nlogn)做法

	int n;n=get_num();
	for(int i=1;i<=n;i++) f[get_num()]=i;
	for(int i=1;i<=n;i++){
		int c=f[get_num()];
		if(c>dp[len]) dp[++len]=c;
		else{
			int l=1,r=len,mid;
			while(l<=r){
				mid=(l+r)>>1;
			    if(dp[mid]>c) r=mid-1;
			    else l=mid+1;
			}dp[l]=c;
		}		
	}
	cout<<len;

二进制拆分

void solv(int n) {
    cnt = 0;
    for (int i = 1; i <= n; i++) {
        int w, k;
        cin >> k >> w;
        for (int j = 1; j <= k; j <<= 1) {
            cnt++;
            v[cnt] = j * w;
            k -= j;
        }
        if (k) {
            cnt++;
            v[cnt] = k * w;
        }
    }
}

数论

快速幂

LL fast_pow(LL a, LL p, LL k) {
    LL ans = (a == 0) ? 0 : 1;  //注意是a不是p	a%=k;
    for (; p; p >>= 1, a = (a * a) % k) {
        if (p & 1) ans = (ans * a) % k;
    }
    return ans;
}

gcd

int gcd(int a, int b) {
    if (b == 0) return a;
    return gcd(b, a % b);
}

exgcd 同余方程

void exgcd(LL a, LL b, LL &x, LL &y) {
    if (b == 0) {
        x = 1, y = 0;
        return;
    }
    exgcd(b, a % b, x, y);
    LL x2 = x, y2 = y;
    x = y2;
    y = x2 - (a / b) * y2;  //手推即可
}

线性筛素数

{
    int n, m;
    n = get_num();
    m = get_num();
    for (int i = 2; i <= n; i++) {
        if (!vis[i]) pri[++cnt] = i;
        for (int j = 1; j <= cnt && pri[j] * i <= n; j++) {
            vis[i * pri[j]] = 1;  //注意谁%谁 后者%不动
            if (i % pri[j] == 0) break;
        }
    }
    vis[1] = 1;  //注意1首先啥都不是 其次他不是素数	for(int i=1;i<=m;i++){		if(vis[get_num()]) cout<<"No\n";
    else cout << "Yes\n";
}

没有考虑vis[1]=1的情况 详情看日记

矩阵快速幂

const int N = 3;
LL p = 10007;
struct Matrix {
    LL x[N][N];
    Matrix operator*(const Matrix &t) const {
        Matrix ret;
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < N; j++) {
                ret.x[i][j] = 0;
                for (int k = 0; k < N; ++k) {
                    ret.x[i][j] += (x[i][k] * t.x[k][j]) % p;
                    ret.x[i][j] %= p;
                }
            }
        }
        return ret;
    }  // 为了防止奇怪的错误,最好写上构造函数
    Matrix() { memset(x, 0, sizeof(x)); }
    Matrix(const Matrix &t) { memcpy(x, t.x, sizeof(x)); }
};
Matrix quick_pow(Matrix a, LL x) {
    Matrix ret;
    for (int i = 0; i < N; i++) {
        ret.x[i][i] = 1;
    }
    while (x) {
        if (x & 1) ret = ret * a;
        a = a * a;
        x >>= 1;
    }
    return ret;
}
int main() {
    int T;
    cin >> T;
    while (T--) {
        LL n;
        cin >> n;
        Matrix a;
        a.x[0][0] = a.x[1][1] = a.x[2][0] = a.x[2][1] = a.x[2][2] = 2;
        a.x[0][2] = a.x[1][2] = 1;
        Matrix P = quick_pow(a, n);
        cout << P.x[0][0] << '\n';
    }
    return 0;
}

fast_pow里面p>>=1 写的p>>1 get_num()没改LL

乘法逆元

{
    LL n, p;
    cin >> n >> p;
    inv[1] = 1 % p;
    cout << inv[1] << '\n';
    for (int i = 2; i <= n; i++) {
        inv[i] = (p - p / i) * inv[p % i] % p;  //由p%i+(p/i)*i=p开始
        cout << inv[i] << '\n';
    }
}

字符串

KMP

void getNext(const string &p) {
    int len = p.size();
    nxt[0] = 0;
    for (int i = 1, j = 0; i < len; ++i) {
        while (j && p[i] != p[j]) j = nxt[j - 1];
        if (p[i] == p[j]) j++;
        nxt[i] = j;
    }
}
int KMP(const string &s, const string &p) {
    int ans = 0;
    getNext(p);
    int len1 = s.size(), len2 = p.size();
    for (int i = 0, j = 0; i < len1; ++i) {
        while (j && s[i] != p[j]) j = nxt[j - 1];
        if (s[i] == p[j]) j++;
        if (j == len2) {
            ans++;
            j = nxt[j - 1];
        }
    }
    return ans;
}

Trie

struct Trie {
    static const int N = 1e6 + 7, charset = 2;
    int tot, root, child[N][charset], flag[N];
    Trie() { clear(); }
    void clear() {
        memset(child, -1, sizeof(child));
        memset(flag, 0, sizeof(flag));
        root = tot = 0;
    }
    void insert(const string &s) {
        int now = root;
        for (int i = 0; i < (int)s.size(); i++) {
            int x = s[i] - 'a';
            if (child[now][x] == -1) {
                child[now][x] = ++tot;
                flag[now] = 0;
            }
            now = child[now][x];
        }
        flag[now] = 1;
    }
    // 查询字典树中是否存在某个完整的字符串是s的前缀
    bool query(const string &s) {
        int now = root;
        for (int i = 0; i < (int)s.size(); i++) {
            int x = s[i] - 'a';
            if (child[now][x] == -1) return false;
            if (flag[now]) return true;
            now = child[now][x];
        }
        return false;
    }
};

STL

Map

技巧

MAP初始化

// 方法一
map<char, int> M1({{'Q', 0}, {'W', 1}, {'E', 2}, {'R', 3}});
// 方法二:采用C++11新特性:
// C++11 还把初始化列表的概念绑定到了类型上,并将其称之为 std::initializer_list,允许构造函数或其他函数像参数一样使用初始化列表,
map<char, int> M2{{'Q', 0}, {'W', 1}, {'E', 2}, {'R', 3}};

split

vector<string> split(const string& s, char c) {  //分隔文件名
    vector<string> res;
    string tmp;
    stringstream ss(s);
    while (getline(ss, tmp, c)) res.push_back(tmp);  //res保存整体
    return res;
}
// std::vector<std::string> split(const std::string& line, char c) {
//     std::stringstream stm(line);
//     std::vector<std::string> ans;
//     std::string tmp;
//     while (std::getline(stm, tmp, c)) ans.push_back(tmp);
//     return ans;
// }
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值