ACM模板

*upd : 10.23

图论

单源最短路径(dijkstra)

#include<bits/stdc++.h>
#define LL long long
using namespace std;
const int N=2e5+5;
const LL INF=0x3f3f3f3f3f3f3f3f;

struct Dijkstra {
	struct Edge {
		int to;LL val;
	};
	struct Node {
		LL dis;int key;
		friend bool operator < (const Node &x,const Node &y) {
			return x.dis>y.dis;
		}
	};
	bool vis[N];
	int n,m,s;
	LL dis[N];
	vector<Edge>G[N];
	priority_queue<Node>Q;
	void init(int _n,int _s) {
		n=_n,s=_s;
		for (int i=0;i<=n;i++) G[i].clear();
		for (int i=1;i<=n;i++) dis[i]=INF;
	}
	void addEdge(int from,int to,LL val) {
		G[from].push_back({to,val});
	}
	void go() {
		dis[s]=0;
		Q.push({0,s});
		while(!Q.empty()) {
			Node top=Q.top(); Q.pop();
			int now=top.key;
			if (vis[now]) continue;
			vis[now]=1;
			for (int i=0;i<G[now].size();i++) {
				int to=G[now][i].to;
				if (dis[to]>dis[now]+G[now][i].val) {
					dis[to]=dis[now]+G[now][i].val;
					if (!vis[to]) Q.push({dis[to],to});
				}
			}
		}
	}
}dijkstra;

int n,m,s;

int main() {
	cin>>n>>m>>s;
	dijkstra.init(n,s);
	for (int i=1;i<=m;i++) {
		int u,v,w;
		scanf("%d%d%d",&u,&v,&w);
		dijkstra.addEdge(u,v,w);
	}
	dijkstra.go();
	for (int i=1;i<=n;i++) printf("%lld ",dijkstra.dis[i]);
	return 0;
}

树的重心

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 1e5+5;
int ans = N,head[N],nxt[N*2],e[N*2],tot,n;//无向图开两倍空间
bool st[N];
void add(int u,int v) {
    e[tot] = v;
    nxt[tot] = head[u];
    head[u] = tot++;
}
int dfs(int u) {
    st[u] = true;
    int cnt = 0,sum = 0;
    for(int i=head[u];i != -1;i = nxt[i]) {
        int j = e[i];
        if(!st[j]) {
            int s = dfs(j);
            cnt = max(cnt,s);//每次统计以u为根的子树中点的个数的最大值
            sum += s;
        }
    }
    cnt = max(cnt,n - sum - 1);//与剩余的点的个数比较
    ans = min(ans,cnt);//比较各个最大值中的最小值
    return sum + 1;//返回以u为根的子树中的点的个数(加上本身)
}
int main() {
    cin >> n;
    int l,r;
    memset(head,-1,sizeof(head));
    for(int i=0;i<n;i++) {
        cin >> l >> r;
        add(l,r);
        add(r,l);
    }
    dfs(1);
    cout << ans;
    return 0;
}

虚树+LCA优化

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

const int N=2e5+5;

int pre[N][25],dfn[N],deep[N],sta[N],TOP,lg[N];

int A[N],n,s,NODE,x,y;

ll ans=0;

vector<int>G[N];
vector<int>E[N];
vector<int>D[N];

void DFS(int x,int fa) {
    int to;
    dfn[x]=++NODE;
    deep[x]=deep[fa]+1;
    D[deep[x]].push_back(x);
    pre[x][0]=fa;
    for (int i=1;(1<<i)<=deep[x];i++) pre[x][i]=pre[pre[x][i-1]][i-1];
    for (int i=0;i<G[x].size();i++) {
        to=G[x][i];
        if (to!=fa)
            DFS(to,x);
    }
}

int LCA(int x,int y) {
    if (deep[x]<deep[y]) swap(x,y);
    while(deep[x]>deep[y]) x=pre[x][lg[deep[x]-deep[y]]-1];
    if (x==y) return x;
    for (int i=lg[deep[x]]-1;i>=0;i--)
        if (pre[x][i]!=pre[y][i])
            x=pre[x][i],y=pre[y][i];
    return pre[x][0];
}

void Insert(int x) {
    if (TOP==1) {
        if (sta[TOP]!=x) sta[++TOP]=x;
        return;
    }
    int lca=LCA(x,sta[TOP]);
    while(TOP>=2 && dfn[sta[TOP-1]]>=dfn[lca]) {
        E[sta[TOP-1]].push_back(sta[TOP]);
        TOP--;
    }
    if (sta[TOP]!=lca) E[lca].push_back(sta[TOP]),sta[TOP]=lca;
    sta[++TOP]=x;
}

ll solve(int x) {
    if (E[x].empty())
        return 1LL*A[x];
    ll ret=0;
    for (int i=0;i<E[x].size();i++) {
        int to=E[x][i];
        ll sol=solve(to);
        if (sol!=0)
            ret+=max(1LL,sol-(deep[to]-deep[x]));
    }
    E[x].clear();
    return ret;
}

int main() {
    cin>>n>>s;
    for (int i=1;i<=n;i++) lg[i]=lg[i-1]+(1<<(lg[i-1])==i);
    for (int i=1;i<=n;i++) scanf("%d",&A[i]);
    for (int i=1;i<=n-1;i++) {
        scanf("%d%d",&x,&y);
        G[x].push_back(y);
        G[y].push_back(x);
    }
    DFS(s,0);
    for (int i=1;!D[i].empty();i++) {
        sort(D[i].begin(),D[i].end(),[&](int u,int v){return dfn[u]<dfn[v];});
        TOP=0;
        sta[++TOP]=s;
        for (int j=0;j<D[i].size();j++) {
            Insert(D[i][j]);
        }
        while(TOP>1) {
            E[sta[TOP-1]].push_back(sta[TOP]);
            TOP--;
        }
        ll sol=solve(s);
        if (sol) ans+=max(1LL,sol-1);
    }
    printf("%lld",ans);
    return 0;
}

点分治

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

const int N = 1e4 + 5, M = 1e7 + 5, P = 1e2 + 5, INF = 0x3f3f3f3f;

struct Edge {
    int to, v;
};

struct BIT {
    int t[N<<1];
    int lowbit(int x) {return x &(-x);}
    void add(int x, int v) {
        while(x < N) {
            t[x] += v;
            x += lowbit(x);
        }
    }
    int ask(int x) {
        int res = 0;
        while(x) {
            res += t[x];
            x -= lowbit(x);
        }
        return res;
    }
}bit;

int n, m, k, q[P], cnt[P], bucket[M];

vector<int> D;

/**variables of tree divide*/
int tot, sz[N], MN, rt;

bool vis[N];

vector<Edge> G[N];

int Getroot(int x, int f) {
    int sum = 0, mx = 0, tmp;
    for (auto T : G[x]) {
        int to = T.to;
        if (vis[to] || to == f) continue;
        tmp = Getroot(to, x);
        sum += tmp;
        mx = max(mx, tmp);
    }
    sum++;
    mx = max(mx, tot - sum);
    if (mx < MN) {
        MN = mx;
        rt = x;
    }
    return sum;
}

void Getsz(int x, int f) {
    sz[x] = 0;
    for (auto T : G[x]) {
        int to = T.to;
        if (vis[to] || to == f) continue;
        Getsz(to, x);
        sz[x] += sz[to];
    }
    sz[x]++;
}

void Getdis(int x, int len, int f) {
    D.push_back(len);
    for (auto T : G[x]) {
        int to = T.to, v = T.v;
        if (vis[to] || to == f) continue;
        Getdis(to, len + v, x);
    }
}

void calc(int x, int len, int type) {
    D.clear();
    Getdis(x, len, -1);
    for (int y : D) {
        if (y > M) continue;
        for (int i = 1; i <= m; i++) {
            if (q[i] - y < 0) continue;
            cnt[i] += type * bucket[q[i] - y];
        }
        bucket[y]++;
    }
    for (int y : D) {
        if (y > M) continue;
        bucket[y]--;
    }
}

void solve(int x) {
    vis[x] = 1;
    calc(x, 0, 1);
    for (auto T : G[x]) {
        int to = T.to, v = T.v;
        if (vis[to]) continue;
        calc(to, v, -1);
        tot = sz[to], MN = INF;
        Getroot(to, -1);
        Getsz(rt, -1);
        solve(rt);
    }
}

int main() {
    cin >> n >> m;
    for (int i = 1, u, v, w; i <= n - 1; i++) {
        scanf("%d %d %d", &u, &v, &w);
        G[u].push_back({v, w});
        G[v].push_back({u, w});
    }
    for (int i = 1; i <= m; i++) scanf("%d", &q[i]);
    tot = n, MN = INF;
    Getroot(1, -1);
    Getsz(rt, -1);
    solve(rt);
    for (int i = 1; i <= m; i++) {
        printf("%s\n", cnt[i] ? "AYE" : "NAY");
    }
    return 0;
}

树链剖分(轻重链剖分)

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

const int N=1e5+5;

LL q[N];

int n,m,r,p,ord[N];

struct segTree {
	LL t[N<<2];
	LL lztag[N<<2];
	void init() {
		memset(t,0,sizeof(t));
		memset(lztag,0,sizeof(lztag));
	}
	void pushdown(int o,int l,int r) {
		if (lztag[o]) {
			int mid=(l+r)>>1;
			t[o*2]+=lztag[o]*(mid-l+1);
			t[o*2]%=p;
			t[o*2+1]+=lztag[o]*(r-mid);
			t[o*2+1]%=p;
			lztag[o*2]+=lztag[o];
			lztag[o*2]%=p;
			lztag[o*2+1]+=lztag[o];
			lztag[o*2+1]%=p;
			lztag[o]=0;
		}
	}
	void pushup(int o,int l,int r) {
		t[o]=(t[o*2]+t[o*2+1])%p;
	}
	void build(int o,int l,int r) {
		if (l==r) {
			t[o]=ord[l]%p;
			return;
		}
		int mid=(l+r)>>1;
		build(o*2,l,mid);
		build(o*2+1,mid+1,r);
		pushup(o,l,r);
	}
	void modify(int o,int l,int r,int tl,int tr,int v) {
		if (tl<=l && r<=tr) {
			t[o]+=1LL*v*(r-l+1);
			t[o]%=p;
			lztag[o]+=v;
			lztag[o]%=p;
			return;
		}
		int mid=(l+r)>>1;
		pushdown(o,l,r);
		if (tl<=mid) modify(o*2,l,mid,tl,tr,v);
		if (tr>mid) modify(o*2+1,mid+1,r,tl,tr,v);
		pushup(o,l,r);
	}
	LL query(int o,int l,int r,int tl,int tr) {
		if (tl<=l && tr>=r) return t[o];
		int mid=(l+r)>>1;
		pushdown(o,l,r);
		if (tr<=mid) return query(o*2,l,mid,tl,tr)%p;
		if (tl>mid) return query(o*2+1,mid+1,r,tl,tr)%p;
		return (query(o*2,l,mid,tl,tr)+query(o*2+1,mid+1,r,tl,tr))%p;
	}
}ST;

int sz[N],dep[N],son[N],fa[N],top[N],num[N],cnt;

vector<int>G[N];

void init() {
	memset(sz,0,sizeof(sz));
	cnt=0;
	fa[r]=-1;
	dep[r]=1;
	top[r]=r;
}

void dfs1(int x) {
	int mxson=-1;
	son[x]=-1;
	for (auto to:G[x]) {
		if (to==fa[x]) continue;
		dep[to]=dep[x]+1;
		fa[to]=x;
		dfs1(to);
		if (sz[to]>mxson) mxson=sz[to], son[x]=to;
		sz[x]+=sz[to];
	}
	sz[x]++;
}
void dfs2(int x,int tp) {
	num[x]=++cnt;
	ord[cnt]=q[x];
	top[x]=tp;
	if (~son[x]) dfs2(son[x],tp);
	for (auto to:G[x]) {
		if (to==fa[x] || to==son[x]) continue;
		dfs2(to,to);
	}
}
void chainModify(int x,int y,int z) {
	while(top[x]!=top[y]) {
		if (dep[top[x]]<dep[top[y]]) swap(x,y);
		ST.modify(1,1,n,num[top[x]],num[x],z);
		x=fa[top[x]];
	}
	if (dep[x]>dep[y]) swap(x,y);
	ST.modify(1,1,n,num[x],num[y],z);
}
LL chainQuery(int x,int y) {
	LL res=0;
	while(top[x]!=top[y]) {
		if (dep[top[x]]<dep[top[y]]) swap(x,y);
		res+=ST.query(1,1,n,num[top[x]],num[x]);
		res%=p;
		x=fa[top[x]];
	}
	if (dep[x]>dep[y]) swap(x,y);
	res+=ST.query(1,1,n,num[x],num[y]);
	res%=p;
	return res;
}
void subtreeModify(int x,int z) {
    ST.modify(1,1,n,num[x],num[x]+sz[x]-1,z);
}
LL subtreeQuery(int x) {
    return ST.query(1,1,n,num[x],num[x]+sz[x]-1);
}

int main() {
	cin>>n>>m>>r>>p;
	for (int i=1;i<=n;i++) {
		scanf("%lld",&q[i]);
		q[i]%=p;
	}
	for (int i=1;i<=n-1;i++) {
		int u,v;
		scanf("%d%d",&u,&v);
		G[u].push_back(v);
		G[v].push_back(u);
	}
	init();
	dfs1(r);
	dfs2(r,r);
	ST.build(1,1,n);
	for (int i=1;i<=m;i++) {
		int opt,x,y;
		LL z;
		scanf("%d",&opt);
		if (opt==1) {
			scanf("%d%d%lld",&x,&y,&z);
			z%=p;
			chainModify(x,y,z);
		}
		if (opt==2) {
			scanf("%d%d",&x,&y);
			printf("%lld\n",chainQuery(x,y));
		}
		if (opt==3) {
			scanf("%d%lld",&x,&z);
			z%=p;
			subtreeModify(x,z);
		}
		if (opt==4) {
			scanf("%d",&x);
			printf("%lld\n",subtreeQuery(x));
		}
	}
	return 0;
}

动态树LCT

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

const int N=1e5+5,INF=0x3f3f3f3f;

struct Link_Cut_Tree{
    int top,root,ch[N][2],ff[N],val[N],xr[N],tag[N],q[N];
    bool isroot(int x) {
        return ch[ff[x]][0]!=x && ch[ff[x]][1]!=x;
    }
    void push_up(int x) {
        xr[x]=xr[ch[x][0]]^xr[ch[x][1]]^val[x];
    }
    void push_down(int x) {
        if (tag[x]) {
            swap(ch[x][0],ch[x][1]);
            tag[ch[x][0]]^=1;
            tag[ch[x][1]]^=1;
            tag[x]=0;
        }
    }
    void Rotate(int x) {
        int y=ff[x],z=ff[y],k=ch[y][1]==x;
        if (!isroot(y)) {
            ch[z][ch[z][1]==y]=x;
        }
        ff[x]=z;
        ch[y][k]=ch[x][k^1],ff[ch[y][k]]=y;
        ch[x][k^1]=y,ff[y]=x;
        push_up(y);push_up(x);
    }
    void Splay(int x) {
        top=1;q[top]=x;
        for (int i=x;!isroot(i);i=ff[i]) q[++top]=ff[i];
        for (int i=top;i;i--) push_down(q[i]);
        while(!isroot(x)) {
            int y=ff[x],z=ff[y];
            if (!isroot(y)) {
                if ((ch[y][0]==x)^(ch[z][0]==y)) Rotate(x);
                else Rotate(y);
            }
            Rotate(x);
        }
    }
    void Access(int x) {
        for (int y=0;x;y=x,x=ff[x]) {
            Splay(x);ch[x][1]=y;push_up(x);
        }
    }
    void Makeroot(int x) {
        Access(x);Splay(x);
        tag[x]^=1;
        push_down(x);
    }
    int Findroot(int x) {
        Access(x); Splay(x);
        push_down(x);
        while(ch[x][0]) {
            push_down(x);x=ch[x][0];
        }
        Splay(x);
        return x;
    }
    void Split(int x,int y) {
        Makeroot(x);
        Access(y); Splay(y);
    }
    void Link(int x,int y) {
        Makeroot(x);
        if (Findroot(y)==x) return;
        ff[x]=y;
    }
    void Cut(int x,int y) {
        Makeroot(x);
        if (Findroot(y)!=x || ff[y]!=x || ch[y][0]) return;
        ff[y]=ch[x][1]=0;
        push_up(x);
    }
    int Query(int x,int y) {
        Split(x,y);
        return xr[y];
    }
    void Modify(int x,int y) {
        val[x]=y; Makeroot(x);
    }
}lct;

int n,m;

int main() {
    cin>>n>>m;
    for (int i=1;i<=n;i++) scanf("%d",&lct.val[i]),lct.xr[i]=lct.val[i];
    for (int i=1;i<=m;i++) {
        int opt,x,y;
        scanf("%d%d%d",&opt,&x,&y);
        switch(opt) {
            case 0:printf("%d\n",lct.Query(x,y));break;
            case 1:lct.Link(x,y);break;
            case 2:lct.Cut(x,y);break;
            case 3:lct.Modify(x,y);break;
        }
    }
    return 0;
}

最大流Dinic

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

const int N=5e3+5;

//理论上界O(N^2*M)
//二分图最大匹配时间复杂度O(sqrt(N)*M)
struct Dinic{
	struct Edge{
		int to;LL v;int rev;
	};
	int n,s,t,dep[N],_cur[N];
	bool used[N];
	vector<Edge>G[N];
	queue<int>L;
	void init(int n_,int s_,int t_) {
		n=n_,s=s_,t=t_;
		for (int i=0;i<=n;i++) G[i].clear();
	}
	void addEdge(int x,int y,LL v) {
		G[x].push_back({y,v,G[y].size()});
		G[y].push_back({x,0,G[x].size()-1});
	}
	bool bfs() {
		memset(used,0,sizeof(used));
		dep[s]=1,used[s]=1;
		L.push(s);
		while(!L.empty()) {
			int cur=L.front();
			L.pop();
			for (int i=0;i<G[cur].size();i++) {
				Edge &e=G[cur][i];
				if (!used[e.to] && e.v>0) {
					dep[e.to]=dep[cur]+1;
					used[e.to]=1;
					L.push(e.to);
				}
			}
		}
		return used[t];
	}
	LL dfs(int c,LL flow) {
		if (c==t ||flow==0) return flow;
		LL ret=0,f;
		for (int &i=_cur[c];i<G[c].size();i++) {
			Edge &e=G[c][i];
			if (dep[e.to]==dep[c]+1 && (f=dfs(e.to,min(flow,e.v)))>0) {
				ret+=f,flow-=f,e.v-=f;
				G[e.to][e.rev].v+=f;
				if (!flow) break;
			}
		}
		return ret;
	}
	LL go() {
		LL ans=0;
		while(bfs()) {
			memset(_cur,0,sizeof(_cur));
			ans+=dfs(s,1LL*100*INT_MAX);
		}
		return ans;
	}
}dinic;

int n,m,e,s,t;
int main() {
	cin>>n>>m>>s>>t;
	dinic.init(n,s,t);
	for (int i=1;i<=m;i++) {
		int u,v,w;
		scanf("%d%d%d",&u,&v,&w);
		dinic.addEdge(u,v,w);
	}
	printf("%lld\n",dinic.go());
	return 0;
}

最大流最小割定理(集合划分)

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

const int N=100000,INF=0x3f3f3f3f;

double a,b[55][55];

int T,n,ac,sum;

ll s,t,dep[N];

int _cur[N];

struct Edge{int to;ll v;int rev;};

vector<Edge>G[N];

void addEdge(int x,int y,ll v)
{
    G[x].push_back((Edge){y,v,(int)G[y].size()});
    G[y].push_back((Edge){x,0,(int)G[x].size()-1});
}
bool bfs()
{
    bool used[50050];
    memset(used,0,sizeof(used));
    dep[s]=1,used[s]=1;
    queue<int>L;
    L.push(s);
    while(!L.empty())
    {
        int cur=L.front();
        L.pop();
        for (int i=0;i<G[cur].size();i++)
        {
            Edge &e=G[cur][i];
            if (!used[e.to] && e.v>0)
            {
                dep[e.to]=dep[cur]+1;
                used[e.to]=1;
                L.push(e.to);
            }
        }
    }
    if (used[t]) return true;
    else return false;
}
ll dfs(int c,ll flow)
{
    if (c==t) return flow;
    if (flow==0) return flow;
    ll ret=0,f;
    for (int &i=_cur[c];i<G[c].size();i++)
    {
        Edge &e=G[c][i];
        if (dep[e.to]==dep[c]+1 && (f=dfs(e.to,min(flow,e.v)))>0)
        {
            ret+=f;
            flow-=f;
            e.v-=f;
            G[e.to][e.rev].v+=f;
            if (flow==0) break;
        }
    }
    return ret;
}
ll Dinic()
{
    ll ans=0;
    while(bfs())
    {
        memset(_cur,0,sizeof(_cur));
        ans+=dfs(s,1ll*100*INT_MAX);
    }
    return ans;
}

void solve()
{
	cin>>n;
	s=0,t=n+n*n*2+1;
	for (int i=s;i<=t;i++) G[i].clear();
	sum=0;
	for (int i=1;i<=n;i++)
	{
		scanf("%lf",&a);
		ac=round(a*100);
		addEdge(s,i,ac);
		sum+=ac;
	}
	for (int i=1;i<=n;i++)
	{
		scanf("%lf",&a);
		ac=round(a*100);
		addEdge(i,t,ac);
		sum+=ac;
	}
	for (int i=1;i<=n;i++)
		for (int j=1;j<=n;j++)
		{
			scanf("%lf",&b[i][j]);
			ac=round((b[i][j])*100);
			sum+=ac*2;
			addEdge(s,n+((i-1)*n+j)*2-1,ac);
			addEdge(n+((i-1)*n+j)*2,t,ac);
			addEdge(n+((i-1)*n+j)*2-1,i,INF);
			addEdge(n+((i-1)*n+j)*2-1,j,INF);
			addEdge(i,n+((i-1)*n+j)*2,INF);
			addEdge(j,n+((i-1)*n+j)*2,INF);
		}
	ll mincut=Dinic();
	double ans=(sum-mincut)/100.0;
	printf("%.2lf\n",ans);
}

int main()
{
    cin>>T;
    while(T--) solve();
    return 0;
}

最小费用最大流(MCMF)

#include<bits/stdc++.h>
#define LL long long
using namespace std;
const int N=1e5+5;
const int INF=0x3f3f3f3f3f3f3f3f;

struct MCMF {
	struct E{
		int from,to;
		LL flow,dis;
	};
	queue<int>Q;
	vector<E>edge;
	vector<int>G[N];
	bool vis[N];
	int n,m,s,t,pre[N],last[N];
	LL dis[N],flow[N],maxflow,mincost;
	void init(int _n,int _s,int _t) {
		n=_n,s=_s,t=_t;
		for (int i=0;i<=n;i++) G[i].clear();
		edge.clear();m=0;
		maxflow=mincost=0;
	}
	void addEdge(int from,int to,int flow,int cost) {
		edge.push_back({from,to,flow,cost});
		edge.push_back({to,from,0,-cost});
		G[from].push_back(m++);
		G[to].push_back(m++);
	}
	bool spfa(int s,int t) {
		for (int i=0;i<=n;i++) {
			dis[i]=INF;flow[i]=INF;vis[i]=0;
		}
		Q.push(s);dis[s]=0;vis[s]=1;pre[t]=-1;
		while(!Q.empty()) {
			int now=Q.front();
			Q.pop();
			vis[now]=0;
			for (int i:G[now]) {
				if (edge[i].flow && dis[edge[i].to]>dis[now]+edge[i].dis) {
					dis[edge[i].to]=dis[now]+edge[i].dis;
					pre[edge[i].to]=now;
					last[edge[i].to]=i;
					flow[edge[i].to]=min(flow[now],edge[i].flow);
					if (!vis[edge[i].to]) {
						vis[edge[i].to]=1;
						Q.push(edge[i].to);
					}
				}
			}
		}
		return pre[t]!=-1;
	}
	LL go() {
		while(spfa(s,t)) {
			int now=t;
			maxflow+=flow[t];
			mincost+=flow[t]*dis[t];
			while(now!=s) {
				edge[last[now]].flow-=flow[t];
				edge[last[now]^1].flow+=flow[t];
				now=pre[now];
			}
		}
		return mincost;
	}
}mcmf;

int n,m,s,t;

int main() {
	cin>>n>>m>>s>>t;
	mcmf.init(n,s,t);
	for (int i=1;i<=m;i++) {
		int u,v;LL w,f;
		scanf("%d%d%lld%lld",&u,&v,&w,&f);
		mcmf.addEdge(u,v,w,f);
	}
	mcmf.go();
	printf("%lld %lld\n",mcmf.maxflow,mcmf.mincost);
	return 0;
}

二分图最大匹配(匈牙利算法)(最小点覆盖=最大匹配)

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

const int MAXN=5e2+5;

vector<int>G[MAXN];

int n,m,e,ans,u,v;

int vistime[MAXN],mch[MAXN];

bool dfs(int u,int tag) {
    if (vistime[u]==tag) return 0;
    vistime[u]=tag;
    for (auto v:G[u])
        if (mch[v]==0 || dfs(mch[v],tag)) {
            mch[v]=u;
            return 1;
        }
    return 0;
}

int main() {
    cin>>n>>m>>e;
    for (int i=1;i<=e;i++) {
        scanf("%d%d",&u,&v);
        G[u].push_back(v);
    }
    for (int i=1;i<=n;i++)
        if (dfs(i,i)) ans++;
    printf("%d\n",ans);
    return 0;
}

一般图最大匹配(Edmonds带花树)

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MAX_N=1000+20;
const int INF=0x3f3f3f3f;

int N,M;
int n,m;
int d[MAX_N];

bool Graph[MAX_N][MAX_N];
int Match[MAX_N];
bool InQueue[MAX_N],InPath[MAX_N],InBlossom[MAX_N];
int Head,Tail;
int Queue[MAX_N];
int Start,Finish;
int NewBase;
int Father[MAX_N],Base[MAX_N];
int Count;

void CreatGraph(){//O(n^3)
    int u,v;
    vector<int>V[MAX_N];
    memset(Graph,false,sizeof(Graph));
    int tot=1;
    for (int i=1;i<=n;i++)
    {
        scanf("%d",&d[i]);
        for (int j=1;j<=d[i];j++) V[i].push_back(tot++);
    }
    for (int i=1;i<=m;i++)
    {
        scanf("%d%d",&u,&v);
        int x=tot++,y=tot++;
        for (int j=0;j<d[u];j++) Graph[V[u][j]][x]=Graph[x][V[u][j]]=1;
        for (int j=0;j<d[v];j++) Graph[V[v][j]][y]=Graph[y][V[v][j]]=1;
        Graph[x][y]=Graph[y][x]=1;
    }
    N=tot-1;
}
void Push(int u){
    Queue[Tail]=u;
    Tail++;
    InQueue[u]=true;
}
int Pop(){
    int res=Queue[Head];
    Head++;
    return res;
}
int FindCommonAncestor(int u,int v){
    memset(InPath,false,sizeof(InPath));
    while(1){
        u=Base[u];
        InPath[u]=1;
        if(u==Start)break;
        u=Father[Match[u]];
    }
    while(1){
        v=Base[v];
        if(InPath[v])break;
        v=Father[Match[v]];
    }
    return v;
}
void ResetTrace(int u){
    int v;
    while(Base[u]!=NewBase){
        v=Match[u];
        InBlossom[Base[u]]=InBlossom[Base[v]]=1;
        u=Father[v];
        if(Base[u]!=NewBase)Father[u]=v;
    }
}
void BloosomContract(int u,int v){
    NewBase=FindCommonAncestor(u,v);
    memset(InBlossom,false,sizeof(InBlossom));
    ResetTrace(u);
    ResetTrace(v);
    if(Base[u]!=NewBase)Father[u]=v;
    if(Base[v]!=NewBase)Father[v]=u;
    for(int tu=1;tu<=N;tu++){
        if(InBlossom[Base[tu]]){
            Base[tu]=NewBase;
            if(!InQueue[tu])Push(tu);
        }
    }
}
void FindAugmentingPath(){
    memset(InQueue,false,sizeof(InQueue));
    memset(Father,0,sizeof(Father));
    for(int i=1;i<=N;i++){
        Base[i]=i;
    }
    Head=Tail=1;
    Push(Start);
    Finish=0;
    while(Head<Tail){
        int u=Pop();
        for(int v=1;v<=N;v++){
            if(Graph[u][v]&&(Base[u]!=Base[v])&&(Match[u]!=v)){
                if((v==Start)||((Match[v]>0)&&Father[Match[v]]>0))BloosomContract(u,v);
                else if(Father[v]==0){
                    Father[v]=u;
                    if(Match[v]>0)Push(Match[v]);
                    else{
                        Finish=v;
                        return;
                    }
                }
            }
        }
    }
}
void AugmentPath(){
    int u,v,w;
    u=Finish;
    while(u>0){
        v=Father[u];
        w=Match[v];
        Match[v]=u;
        Match[u]=v;
        u=w;
    }
}
void Edmonds(){
    memset(Match,0,sizeof(Match));
    for(int u=1;u<=N;u++){
        if(Match[u]==0){
            Start=u;
            FindAugmentingPath();
            if(Finish>0)AugmentPath();
        }
    }
}
void PrintMatch(){
    Count=0;
    for(int u=1;u<=N;u++){
        if(Match[u]>0)Count++;
    }
    if(Count==N)printf("Yes\n");
    else printf("No\n");
}
int main(){
    while(scanf("%d%d",&n,&m)==2){
        CreatGraph();
        Edmonds();
        PrintMatch();
    }
}

数据结构

树状数组

//第一个位置从1开始(0不可用)
struct BIT{
    LL tr[N];
    int lowbit(int x){ return x&(-x); }
    void clr(int x){
        while(x<SZ)
        {
            tr[x]=0;
            x+=lowbit(x);
        }
    }
    void add(int v,int x){
        while(x<N)
        {
            tr[x]+=v;
            x+=lowbit(x);
        }
    }
    LL sum(int x){
        LL sum=0;
        while(x>0)
        {
            sum+=tr[x];
            x-=lowbit(x);
        }
        return sum;
    }
}bit;
//BIT求MEX
struct BIT {
	int bucket[N],tr[N];
	int lowbit(int x){
    	return x&(-x);
	}
    void add(int x,int v) {
    	if (x<SZ) {
			bucket[x]+=v;
			if (bucket[x]==1 && v==1|| bucket[x]==0 && v==-1)
				while(x<SZ)	{
					tr[x]+=v;
					x+=lowbit(x);
				}
		}
    }
    int sum(int x) {
        int sum=0;
        while(x>0) {
            sum+=tr[x];
            x-=lowbit(x);
        }
        return sum;
    }
    int MEX() {
		int l=1,r=SZ-1;
		while(l<r) {
			int mid=(l+r)>>1;
			if (sum(mid)<mid)
				r=mid;
			else l=mid+1;
		}
		return l;
    }
}bit;

二维树状数组

struct BIT{
    int C[N][N];
    int lowbit(int x) {return x&(-x);}
    void Modify(int i,int j,int delta){
        for(int x=i;x<=a;x+=lowbit(x))
            for(int y=j;y<=b;y+=lowbit(y)) {
                C[x][y]+=delta;
            }
    }
    int Sum(int i,int j)
    {
        int result=0;
        for(int x=i;x>0;x-=lowbit(x)) {
            for(int y=j;y>0;y-=lowbit(y)) {
                result+=C[x][y];
            }
        }
        return result;
    }
}bit;

线段树

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

const int N=1e5+5;

struct Segtree {
	LL t[N<<2],lz[N<<2];
	void push_down(int o,int l,int r) {
		if (lz[o]) {
			int mid=(l+r)>>1;
			t[o*2]+=lz[o]*(mid-l+1);
			t[o*2+1]+=lz[o]*(r-mid);
			lz[o*2]+=lz[o];
			lz[o*2+1]+=lz[o];
			lz[o]=0;
		}
	}
	void push_up(int o,int l,int r) {
		t[o]=t[o*2]+t[o*2+1];
	}
	void update(int o,int l,int r,LL v) {
		t[o]+=v*(r-l+1);
		lz[o]+=v;
	}
	void build(int o,int l,int r) {
		lz[o]=0;
		if (l==r) {
			scanf("%lld",&t[o]);
			return;
		}
		int mid=(l+r)>>1;
		build(o*2,l,mid);
		build(o*2+1,mid+1,r);
		push_up(o,l,r);
	}
	void modify(int o,int l,int r,int tl,int tr,LL v) {
		if (tl<=l && tr>=r) {
			update(o,l,r,v);
			return;
		}
		push_down(o,l,r);
		int mid=(l+r)>>1;
		if (tl<=mid) modify(o*2,l,mid,tl,tr,v);
		if (tr>mid) modify(o*2+1,mid+1,r,tl,tr,v);
		push_up(o,l,r);
	}
	LL query(int o,int l,int r,int tl,int tr) {
		if (tl<=l && r<=tr) return t[o];
		push_down(o,l,r);
		int mid=(l+r)>>1;
		if (tr<=mid) return query(o*2,l,mid,tl,tr);
		if (tl>mid) return query(o*2+1,mid+1,r,tl,tr);
		return query(o*2,l,mid,tl,tr)+query(o*2+1,mid+1,r,tl,tr);
	}
}segtree;

int n,m,x,y,k,op;

int main() {
	cin>>n>>m;
	segtree.build(1,1,n);
	for (int i=1;i<=m;i++) {
		scanf("%d",&op);
		switch (op){
			case 1:
				scanf("%d%d%d",&x,&y,&k);
				segtree.modify(1,1,n,x,y,k);
				break;
			case 2:
				scanf("%d%d",&x,&y);
				printf("%lld\n",segtree.query(1,1,n,x,y));
		}
	}
	return 0;
}

ST表

#include <bits/stdc++.h>

using namespace std;

const int N = 1e5 + 5;

int a[N][21], n, m;

int query(int l, int r) {
    int k = log2(r - l + 1);
    return max(a[l][k], a[r-(1<<k)+1][k]);
}

int main() {
    cin >> n >> m;
    for (int i=1; i<=n; i++) scanf("%d", &a[i][0]);
    for (int i=1; i<=21; i++) {
        for (int j=1; j+(1<<i)-1<=n; j++) {
            a[j][i] = max(a[j][i-1], a[j+(1<<(i-1))][i-1]);
        }
    }
    for (int i=1, l, r; i<=m; i++) {
        scanf("%d %d", &l, &r);
        printf("%d\n", query(l, r));
    }
    return 0;
}

Splay

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

const int N=1e5+5,INF=0x3f3f3f3f;

struct Splay_tree{
    int root=0,ch[N][2],ff[N],sz[N],cnt[N],val[N],points;
    void push_up(int x) {
        sz[x]=sz[ch[x][0]]+sz[ch[x][1]]+cnt[x];
    }
    void Rotate(int x) {
        int y=ff[x],z=ff[y],k=ch[y][1]==x;
        ch[z][ch[z][1]==y]=x,ff[x]=z;
        ch[y][k]=ch[x][k^1],ff[ch[y][k]]=y;
        ch[x][k^1]=y,ff[y]=x;
        push_up(y);push_up(x);
    }
    void Splay(int x,int goal) {
        while(ff[x]!=goal) {
            int y=ff[x],z=ff[y];
            if (z!=goal) {
                if ((ch[z][1]==y) ^ (ch[y][1]==x)) Rotate(x);
                else Rotate(y);
            }
            Rotate(x);
        }
        if (goal==0) root=x;
    }
    void Insert(int x) {
        int u=root,f=0;
        while(u && val[u]!=x) {
            f=u;
            u=ch[u][val[u]<x];
        }
        if (u) cnt[u]++;
        else {
            u=++points;
            if (f) ch[f][x>val[f]]=u;
            ch[u][0]=ch[u][1]=0;
            ff[u]=f; val[u]=x;
            sz[u]=1; cnt[u]=1;
        }
        Splay(u,0);
    }
    void Find(int x) {
        int u=root;
        if (!u) return;
        while(ch[u][x>val[u]] && x!=val[u]) u=ch[u][x>val[u]];
        Splay(u,0);
    }
    int Next(int x,int f) {
        Find(x);
        int u=root;
        if ((val[u]>x && f) || (val[u]<x && !f)) return u;
        u=ch[u][f];
        while(ch[u][f^1]) u=ch[u][f^1];
        return u;
    }
    void Delete(int x) {
        int pre=Next(x,0),nxt=Next(x,1);
        Splay(pre,0);Splay(nxt,pre);
        int del=ch[nxt][0];
        if (cnt[del]>1) {
            cnt[del]--;
            Splay(del,0);
        }
        else {
            ch[nxt][0]=0;
            //Splay(nxt,0);
        }
    }
    int Rank(int x) {
        Find(x);
        return sz[ch[root][0]];
    }
    int K_th(int x) {
        int u=root;
        if (sz[u]<x) return -1;
        while(true) {
            if (sz[ch[u][0]]+cnt[u]<x) {
                x-=sz[ch[u][0]]+cnt[u];
                u=ch[u][1];
            }
            else if (sz[ch[u][0]]>=x) {
                u=ch[u][0];
            }
            else return u;
        }
    }
}splay;

int n,opt,x;

int main() {
    cin>>n;
    splay.Insert(-INF);splay.Insert(INF);
    while(n--) {
        scanf("%d%d",&opt,&x);
        switch(opt) {
            case 1:splay.Insert(x);break;
            case 2:splay.Delete(x);break;
            case 3:printf("%d\n",splay.Rank(x));break;
            case 4:printf("%d\n",splay.val[splay.K_th(x+1)]);break;
            case 5:printf("%d\n",splay.val[splay.Next(x,0)]);break;
            case 6:printf("%d\n",splay.val[splay.Next(x,1)]);break;
        }
    }
    return 0;
}

数学

快速幂

int bin(int x,int p) {
	int res=1;
	for (;p;p>>=1,x=(1ll*x*x)%MOD)
		if (p&1) res=(1ll*res*x)%MOD;
	return res;
}

exgcd扩展欧几里得(求ax+by=0整数解)

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

const int MAXN=3e6+5;

void Exgcd(ll a, ll b, ll &x, ll &y) {
    if (!b) x = 1, y = 0;
    else Exgcd(b, a % b, y, x), y -= a / b * x;
}
int n,p;

int main()
{
    cin>>n>>p;
    for (int i=1;i<=n;i++)
    {
        ll x, y;
        Exgcd (i, p, x, y);
        x = (x % p + p) % p;
        printf ("%d\n", x); //x是a在mod p下的逆元
    }
}

欧拉筛

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

const int N=1e7+5;

int vis[N],prime[N],countPrime;
void getPrime() {
	for (int i=2;i<N;i++) {
		if (!vis[i]) prime[++countPrime]=i;
		for (int j=1;j<=countPrime;j++) {
			if (i*prime[j]>=N) break;
			vis[i*prime[j]]=1;
			if (i%prime[j]==0) break;
		}
	}
}

int main() {
	getPrime();
	printf("%d",countPrime);
	return 0;
}

Min_25筛

#include <bits/stdc++.h>

using namespace std;
typedef long long LL;

const int N = 2e5 + 5;

int vis[N], pr[N], countPr;

void getPrime() {
    for (int i = 2; i < N; i++) {
        if (!vis[i]) pr[++countPr] = i;
        for (int j = 1; j <= countPr; j++) {
            if (i * pr[j] >= N) break;
            vis[i * pr[j]] = 1;
            if (i % pr[j] == 0) break;
        }
    }
}

LL g[N], ans;

LL sum[N], n, w[N];

int id1[N], id2[N], m;

int sqr, K, T;

int bin(int x, int p) {
    int res = 1;
    for (int b = x; p; p >>= 1, b = 1ll * b * b % K)
        if (p & 1) res = 1ll * res * b % K;
    return res;
}

int main() {
    cin >> T;
    getPrime();
    for (int i = 1; i <= countPr; i++) sum[i] = sum[i - 1] + pr[i];
    while (T--) {
        scanf("%lld %d", &n, &K); 
        n++;
        sqr = sqrt(n);
        m = 0;
        int inv2 = bin(2, K - 2);
        for (LL i = 1, j; i <= n; i = j + 1) {
            j = n / (n / i); w[++m] = n / i;
            if (w[m] <= sqr) id1[w[m]] = m;
            else id2[n / w[m]] = m;
            g[m] =(1ll * (1 + w[m]) % K * w[m] % K * inv2 - 1) % K;
        }

        int tot = 0;
        while (1ll * pr[tot] * pr[tot] <= n) tot++;
        tot--;
        clock_t st = clock();
        int cc = 0;
        LL k;
        for (int j = 1; j <= tot; ++j) {
            for (int i = 1; i <= m && 1ll * pr[j] * pr[j] <= w[i]; ++i) {
                cc++;
                k = w[i] / pr[j];
                if (k <= sqr) k = id1[k];
                else k = id2[n / k];
                g[i] = g[i] - 1ll * pr[j] * (g[k] - sum[j - 1]) ;
            }
        }
        ans = (1ll * g[1] % K + ((n + 2) % K) * ((n - 1) % K) % K * inv2 % K - 4 + K) % K;
        printf("%d\n",ans);
    }
    return 0;
}

线性求逆元

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

const int N=3e6+5;

int inv[N],n,p;

void getInv(int n) {
    inv[1] = 1;
    for(int i=2 i<=n;i++)
        inv[i]=1ll*(p-p/i)*inv[p%i]%p;
}

int main() {
    cin>>n>>p;
    getInv(n);
    for (int i=1;i<=n;i++)
        printf("%d\n",inv[i]);
}

二次剩余

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll w;
struct num{
    ll x,y;
};

num mul(num a,num b,ll p)
{
    num ans={0,0};
    ans.x=((a.x*b.x%p+a.y*b.y%p*w%p)%p+p)%p;
    ans.y=((a.x*b.y%p+a.y*b.x%p)%p+p)%p;
    return ans;
}

ll powwR(ll a,ll b,ll p){
    ll ans=1;
    while(b){
        if(b&1)ans=1ll*ans%p*a%p;
        a=a%p*a%p;
        b>>=1;
    }
    return ans%p;
}
ll powwi(num a,ll b,ll p){
    num ans={1,0};
    while(b){
        if(b&1)ans=mul(ans,a,p);
        a=mul(a,a,p);
        b>>=1;
    }
    return ans.x%p;
}

ll solve(ll n,ll p)
{
    n%=p;
    if(p==2)return n;
    if(powwR(n,(p-1)/2,p)==p-1)return -1;//不存在
    ll a;
    while(1)
    {
        a=rand()%p;
        w=((a*a%p-n)%p+p)%p;
        if(powwR(w,(p-1)/2,p)==p-1)break;
    }
    num x={a,1};
    return powwi(x,(p+1)/2,p);
}

int main()
{
	srand(time(0));
    int t;
    scanf("%d",&t);
    while(t--)
    {
        ll n,p;
        scanf("%lld%lld",&n,&p);
        if(!n){
        	printf("0\n");continue;
		}
        ll ans1=solve(n,p),ans2;
        if(ans1==-1)printf("Hola!\n");
        else
        {
            ans2=p-ans1;
            if(ans1>ans2)swap(ans1,ans2);
            if(ans1==ans2)printf("%lld\n",ans1);
            else printf("%lld %lld\n",ans1,ans2);
        }
    }
}

行列式计算/生成树计数

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

const int MOD=998244353,N=1e2+5;

LL a[N][N],ans;

int T,n,m,sign;

int M[N][N],M2[N][N];

struct Edge{
    int u,v,w;
}e[10005];

LL detVal(int n){
    sign=0;LL ans=1;
    for(int i=1;i<=n;i++){
        for(int j=i+1; j<=n; j++){//当前之后的每一行第一个数要转化成0
            int x=i,y=j;
            while(a[y][i]){//利用gcd的方法,不停地进行辗转相除
                LL t=a[x][i]/a[y][i];
                for(int k=i; k<n; k++)
                    a[x][k]=(a[x][k]-a[y][k]*t)%MOD;
                swap(x, y);
            }
            if(x!=i){//奇数次交换,则D=-D'整行交换
                for(int k=1;k<n;k++)
                    swap(a[i][k],a[x][k]);
                sign^= 1;//行列式*-1
            }
        }
        if(!a[i][i]){//斜对角中有一个0,则结果为0
            return 0;
        }
        else ans=ans*a[i][i]%MOD;
    }
    if(sign!=0) ans*=-1;
    if(ans<0) ans+=MOD;
    return ans;
}

int main(){
    cin>>T;
    while(T--) {
        scanf("%d%d",&n,&m);
        memset(M,0,sizeof(M));
        for (int i=1;i<=m;i++) {
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            e[i].u=u;e[i].v=v;e[i].w=w;
        }
        memset(a,0,sizeof(a));
        for (int k=1;k<=m;k++) {
            int i=e[k].u,j=e[k].v;
            a[i][i]++;a[j][j]++;
            a[i][j]--;a[j][i]--;
        }
        LL tot=detVal(n);
        tot=bin(tot,MOD-2);
        ans=0;
        for (int i=0;i<=30;i++)
        {
            memset(M2,0,sizeof(M2));
            memset(a,0,sizeof(a));
            for (int p=1;p<=m;p++) {
                if (e[p].w&(1<<i)) {
                    int j=e[p].u,k=e[p].v;
                    a[j][j]++;a[k][k]++;
                    a[j][k]--;a[k][j]--;
                }
            }
            LL cur=detVal(n-1);
            ans=(ans+(1ll*cur*tot)%M(1<<i))%MOD;
        }
        printf("%lld\n",ans);
    }
    return 0;
}

点和向量旋转

//任意点(x,y),绕一个坐标点(rx0,ry0)逆时针旋转a角度后的新的坐标设为(x0, y0),有公式:
// x0= (x-rx0)*cos(a)-(y-ry0)*sin(a)+rx0 ;
// y0= (x-rx0)*sin(a)+(y-ry0)*cos(a)+ry0 ;

//任意向量(x,y),绕一个坐标点(rx0,ry0)逆时针旋转a角度后的新的向量设为(x0, y0),有公式:
// x0= x*cos(a)-y*sin(a);
// y0= x*sin(a)+y*cos(a);
void Rotate(double &x,double &y,double &vx,double &vy,double x0,double y0,double a)
{
	double x_,vx_,y_,vy_;
	x_=(x-x0)*cos(a)-(y-y0)*sin(a)+x0;
	vx_=vx*cos(a)-vy*sin(a);
	y_=(x-x0)*sin(a)+(y-y0)*cos(a)+y0;
	vy_=vx*sin(a)+vy*cos(a);
	x=x_,y=y_,vx=vx_,vy=vy_;
}

算法

CDQ分治

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

const int N=1e5+5;

struct BIT{
    int tr[N];
    int lowbit(int x){ return x&(-x); }
    void clr(int x){
        while(x<N)
        {
            tr[x]=0;
            x+=lowbit(x);
        }
    }
    void add(int v,int x){
        while(x<N)
        {
            tr[x]+=v;
            x+=lowbit(x);
        }
    }
    int sum(int x){
        int sum=0;
        while(x>0)
        {
            sum+=tr[x];
            x-=lowbit(x);
        }
        return sum;
    }
}bit;

struct node{
    int id,x,y,z;
    bool operator==(node &t){
        return x==t.x && y==t.y && z==t.z;
    }
}A[N],tmp[N];

int n,k,ans[N],cnt[N];

void CDQ(int l,int r)
{
    if (l==r) return;
    int mid=(l+r)>>1;
    CDQ(l,mid);
    CDQ(mid+1,r);
    int p1=l,p2=mid+1,pt=l;
    while(p1!=mid+1 || p2!=r+1)
    {
        if (p1==mid+1 || A[p2].y<A[p1].y && p2!=r+1)
        {
            ans[A[p2].id]+=bit.sum(A[p2].z);
            tmp[pt++]=A[p2];
            p2++;
        }
        else
        {
            bit.add(1,A[p1].z);
            tmp[pt++]=A[p1];
            p1++;
        }
    }
    for (int i=l;i<=mid;i++) bit.clr(A[i].z);
    for (int i=l;i<=r;i++) A[i]=tmp[i];
}

bool cmp(node &a,node &b){
    if (a.x==b.x && a.y==b.y)
        return a.z<b.z;
    else if(a.x==b.x) return a.y<b.y;
    else return a.x<b.x;
}

int main()
{
    cin>>n>>k;
    for (int i=1;i<=n;i++)
    {
        scanf("%d%d%d",&A[i].x,&A[i].y,&A[i].z);
        A[i].id=i;
    }
    sort(A+1,A+1+n,cmp);
    int same=0;
    for (int i=n;i>=2;i--)
    {
        if (A[i]==A[i-1]) ans[A[i-1].id]+=++same;
        else same=0;
    }
    CDQ(1,n);
    for (int i=1;i<=n;i++) cnt[ans[i]]++;
    for (int i=0;i<n;i++) printf("%d\n",cnt[i]);
    return 0;
}

最长递增子序列(LIS)

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

const int N=1000+5,INF=0x3f3f3f3f;

int T,n,m,A[N],dp[N],ans;

int check(int l,int r)
{
	for (int i=l;i<r;i++)
	{
		int j=lower_bound(dp,dp+n,A[i])-dp;
		dp[j]=A[i];
	}
	return n-(lower_bound(dp,dp+n,INF)-dp);
}
int main()
{
	cin>>n;
	for (int i=0;i<n;i++)
	{
		scanf("%d",&A[i]);
		A[n+i]=A[i];
	}
	ans=INF;
	for (int k=0;k<n;k++)
	{
		memset(dp,INF,sizeof(dp));
		ans=min(ans,check(k,k+n));
	}
	cout<<ans;
	return 0;
}

带修莫队

#include <bits/stdc++.h>

using namespace std;
typedef long long LL;

const int N = 2e5 + 5, M = 1e6 + 5;

int n, m;

int a[N], cnt[M], cntq, cntp, pos[N], ans[N], now;

char op;

struct Query{
    int l, r, t, id;
    bool operator < (Query &Q) {
        if (pos[l] != pos[Q.l]) return l < Q.l;
        if (pos[r] != pos[Q.r]) return r < Q.r;
        return t < Q.t;
    }
}q[N];

struct Modify{
    int pos, bef, aft;
}p[N];

void inc(int x) {
    if (++cnt[x] == 1) now++;
}

void del(int x) {
    if (!(--cnt[x])) now--;
}

int main() {
    scanf("%d %d", &n, &m);
    for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
    for (int i = 1, u, v; i <= m; i++) {
        op = getchar();
        while(op != 'Q' && op != 'R') op = getchar();
        scanf("%d%d", &u, &v);
        if (op == 'Q') {
            cntq++;
            q[cntq].l = u;
            q[cntq].r = v;
            q[cntq].t = cntp;
            q[cntq].id = cntq;
        } else {
            cntp++;
            p[cntp].pos = u;
            p[cntp].bef = a[u];
            p[cntp].aft = v;
            a[u] = v;
        }
    }
    LL block = pow(1ll * n, 2.0 / 3.0);
    for (int i = 1; i <= n; i++) pos[i] = i / block;
    sort(q + 1, q + 1 + cntq);
    int l = 1, r = 0, t = cntp;
    for (int i = 1; i <= cntq; i++) {
        int nl = q[i].l, nr = q[i].r, nt = q[i].t;
        while(t < nt) {
            t++;
            int pos = p[t].pos, bef = p[t].bef, aft = p[t].aft;
            if (pos >= l && pos <= r) {
                cnt[bef]--;
                if (cnt[bef] == 0) now--;
                cnt[aft]++;
                if (cnt[aft] == 1) now++;
            }
            a[pos] = aft;
        }
        while(t > nt) {
            int pos = p[t].pos, bef = p[t].bef, aft = p[t].aft;
            if (pos >= l && pos <= r) {
                cnt[aft]--;
                if (cnt[aft] == 0) now--;
                cnt[bef]++;
                if (cnt[bef] == 1) now++;
            }
            a[pos] = bef;
            t--;
        }
        while(l < nl) del(a[l++]);
        while(l > nl) inc(a[--l]);
        while(r < nr) inc(a[++r]);
        while(r > nr) del(a[r--]);
        ans[q[i].id] = now;
    }
    for (int i = 1; i <= cntq; i++) printf("%d\n", ans[i]);
    return 0;
}

树上莫队(带修)

#include <bits/stdc++.h>
#define debug(x) cerr << #x << " = " << x << " "
#define debugl(x) cerr << #x << " = " << x << endl

using namespace std;
typedef long long ll;

const int N = 1e5 + 5;

int n, M, Q, v[N], w[N], c[N];

int f[N], g[N], id[N << 1], pos[N << 1], IDX, TIME, CNT;

int dep[N], pre[N][25], pow_2[25], cnt[N];

bool vis[N];

ll ans, aans[N];

struct Modify{
    int pre, aft, pos;
}m[N];

struct Query{
    int x, y, t, id;
}q[N];

bool cmp(Query Q_, Query Q) {
    if (pos[Q_.x] != pos[Q.x]) return pos[Q_.x] < pos[Q.x];
    if (pos[Q_.y] != pos[Q.y]) return pos[Q_.y] < pos[Q.y];
    return Q_.t < Q.t;
}

vector<int> G[N];

void dfs(int x, int ff) {
    f[x] = ++IDX;
    id[IDX] = x;
    for (int to : G[x]) {
        if (to == ff) continue;
        dep[to] = dep[x] + 1;
        pre[to][0] = x;
        dfs(to, x);
    }
    g[x] = ++IDX;
    id[IDX] = x;
}

int LCA(int x, int y) {
    if (dep[x] < dep[y]) swap(x, y);
    int gap = dep[x] - dep[y];
    for (int i = 20; i >= 0; i--) {
        if (gap >= pow_2[i]) {
            gap -= pow_2[i];
            x = pre[x][i];
        }
    }
    if (x == y) return x;
    for (int i = 20; i >= 0; i--) {
        if (pre[x][i] != pre[y][i]) {
            x = pre[x][i];
            y = pre[y][i];
        }
    }
    return pre[x][0];
}

void add(int pos) {
    vis[pos] ^= 1;
    if (vis[pos]) {
        cnt[c[pos]]++;
        ans = ans + 1ll * w[cnt[c[pos]]] * v[c[pos]];
    }
    else {
        ans = ans - 1ll * w[cnt[c[pos]]] * v[c[pos]];
        cnt[c[pos]]--;
    }
}

int main() {
    cin >> n >> M >> Q;
    for (int i = 1; i <= M; i++) scanf("%d", &v[i]);
    for (int i = 1; i <= n; i++) scanf("%d", &w[i]);
    for (int i = 1; i <= n - 1; i++) {
        int a, b;
        scanf("%d %d", &a, &b);
        G[a].push_back(b);
        G[b].push_back(a);
    }
    for (int i = 1; i <= n; i++) scanf("%d", &c[i]);
    pow_2[0] = 1;
    for (int i = 1; i <= 20; i++) pow_2[i] = pow_2[i - 1] * 2;
    dep[1] = 1;
    dfs(1, -1);
    int block = pow(IDX, 2.0 / 3);
    for (int i = 1; i <= IDX; i++) {
        pos[i] = (i - 1) / block + 1;
    }
    for (int i = 1; i <= 20; i++) {
        for (int j = 1; j <= n; j++) pre[j][i] = pre[pre[j][i - 1]][i - 1];
    }
    for (int i = 1; i <= Q; i++) {
        int t, x, y;
        scanf("%d %d %d", &t, &x, &y);
        if (t == 0) {
            m[++TIME] = {c[x], y, x};
            c[x] = y;
        } else {
            if (f[x] > f[y]) swap(x, y);
            q[++CNT] = {LCA(x, y) == x ? f[x] : g[x], f[y], TIME, CNT};
        }
    }
    sort(q + 1, q + 1 + CNT, cmp);
    int l = 0, r = 0, t = TIME;
    for (int i = 1; i <= CNT; i++) {
        while(t < q[i].t) {
            t++;
            if (vis[m[t].pos]) {
                int pc = m[t].pre;
                int ac = m[t].aft;
                ans -= 1ll * v[pc] * w[cnt[pc]];
                cnt[pc]--;
                cnt[ac]++;
                ans += 1ll * v[ac] * w[cnt[ac]];
            }
            c[m[t].pos] = m[t].aft;
        }
        while(t > q[i].t) {
            if (vis[m[t].pos]) {
                int pc = m[t].pre;
                int ac = m[t].aft;
                ans -= 1ll * v[ac] * w[cnt[ac]];
                cnt[ac]--;
                cnt[pc]++;
                ans += 1ll * v[pc] * w[cnt[pc]];
            }
            c[m[t].pos] = m[t].pre;
            t--;
        }
        while(r < q[i].y) r++, add(id[r]);
        while(l > q[i].x) l--, add(id[l]);
        while(r > q[i].y) add(id[r]), r--;
        while(l < q[i].x) add(id[l]), l++;
        int lca = LCA(id[l], id[r]);
        if (lca != id[l] && lca != id[r]) {
            add(lca);
            aans[q[i].id] = ans;
            add(lca);
        } else aans[q[i].id] = ans;
    }
    for (int i = 1; i <= CNT; i++) printf("%lld\n", aans[i]);
    return 0;
}

数位DP

#include<bits/stdc++.h>
using namespace std;
const int MOD=1e9+7;

const int N=200,M=5000;

int digit[20];
int dp[N][M][2][2];
char n[200];

int dfs(int pos,int del,int eqb,int eqa) {
	if (pos==-1) {
		if (del>2500)
			return 1;
		else return 0;
	}
	if (dp[pos][del][eqb][eqa]!=-1) return dp[pos][del][eqb][eqa];
	int upb=eqb?n[pos]:9;
	int sum=0;
	for (int b=0;b<=upb;b++) {
		for (int a=0;a<=(eqa?b:9);a++) {
			sum=(sum+dfs(pos-1,del+a-b,eqb&&(b==n[pos]),eqa&&(a==b)))%MOD;
		}
	}
	dp[pos][del][eqb][eqa]=sum;
	return sum;
}

int main() {
	scanf("%s",n);
	int len=strlen(n);
	reverse(n,n+len);
	for (int i=0;i<len;i++) n[i]-='0';
	memset(dp,-1,sizeof(dp));
	printf("%d",dfs(len-1,2500,1,1));
	return 0;
}

异或最小生成树

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+5;
const int INF=0x3f3f3f3f;

int l[N<<5],r[N<<5];

struct Edge{
    int t,w;
};

int root,num;

vector<Edge>G[N];

vector<int>P;

int u,v,w,n;

ll tot;

void dfs(int x,int fa,int now) {
    P.push_back(now);
    for (auto to:G[x]) {
        if (to.t!=fa)
            dfs(to.t,x,now^to.w);
    }
}
void MakeTrie(int subroot,int check,int x) {
    if (check==0) return;
    if ((x&check)==0) {
        if (l[subroot]==0) l[subroot]=++num;
        MakeTrie(l[subroot],check>>1,x);
    }
    else {
        if (r[subroot]==0) r[subroot]=++num;
        MakeTrie(r[subroot],check>>1,x);
    }
}
ll dfs3(int a,int b,int check) {
	if (!a || !b) return INF;
    if (check==0) return 0;
    ll t1,t2;
    t1=min(dfs3(l[a],l[b],check>>1),dfs3(r[a],r[b],check>>1));
    if (t1==INF)
		t2=check+min(dfs3(l[a],r[b],check>>1),dfs3(r[a],l[b],check>>1));
	else t2=INF;
    return min(t1,t2);
}
ll dfs2(int subroot,int check) {
    ll ret=0;
    if (l[subroot]) ret+=dfs2(l[subroot],check>>1);
    if (r[subroot]) ret+=dfs2(r[subroot],check>>1);
    if (l[subroot] && r[subroot]) {
        int t1=l[subroot],t2=r[subroot];
        ret+=check+dfs3(t1,t2,check>>1);
    }
    return ret;
}

int main() {
    cin>>n;
    for (int i=1;i<=n-1;i++) {
        scanf("%d%d%d",&u,&v,&w);
        G[u].push_back({v,w});
        G[v].push_back({u,w});
    }
    dfs(0,-1,0);
    sort(P.begin(),P.end());
    P.erase(unique(P.begin(),P.end()),P.end());
    for (auto x:P) {
        MakeTrie(0,1<<30,x);
    }
    printf("%lld\n",dfs2(0,1<<30));
    return 0;
}

字符串

KMP

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

const int N=1e5+5;

struct KMP{
    int nxt[N];
    void getNext(string &t) {
        nxt[0]=-1;
        for (int i=1,j=-1;i<=t.length();i++) {
            while(j!=-1 && t[i-1]!=t[j]) j=nxt[j];
            nxt[i]=++j;
        }
    }
    void getAns(string &s,string &t) {
        int len=t.length();
        for (int i=0,j=0;i<s.length();) {
            if (j==-1 || s[i]==t[j]) i++,j++;
            else j=nxt[j];
            if (j==len) printf("%d\n",i-j+1),j=nxt[j];
        }
    }
}kmp;

string s,t;

int main() {
    cin>>s;
    cin>>t;
    kmp.getNext(t);
    kmp.getAns(s,t);
    for (int i=1;i<=t.length();i++) printf("%d ",kmp.nxt[i]);
}

后缀数组SA

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1e6+5;
int n;
char S[MAXN];
int s[MAXN];
int last[2];
//char s[MAXN];
struct SA {
    int sa[MAXN], ra[MAXN], height[MAXN];
    int t1[MAXN], t2[MAXN], c[MAXN];
    void build(int *str, int n, int m) {
        str[n] = 0;
        n++;
        int i, j, p, *x = t1, *y = t2;
        for (i = 0; i < m; i++) c[i] = 0;
        for (i = 0; i < n; i++) c[x[i] = str[i]]++;
        for (i = 1; i < m; i++) c[i] += c[i - 1];
        for (i = n - 1; i >= 0; i--) sa[--c[x[i]]] = i;
        for (j = 1; j <= n; j <<= 1) {
            p = 0;
            for (i = n - j; i < n; i++) y[p++] = i;
            for (i = 0; i < n; i++) if (sa[i] >= j) y[p++] = sa[i] - j;
            for (i = 0; i < m; i++) c[i] = 0;
            for (i = 0; i < n; i++) c[x[y[i]]]++;
            for (i = 1; i < m; i++) c[i] += c[i - 1];
            for (i = n - 1; i >= 0; i--) sa[--c[x[y[i]]]] = y[i];
            swap(x, y);
            p = 1;
            x[sa[0]] = 0;
            for (i = 1; i < n; i++)
                x[sa[i]] = (y[sa[i - 1]] == y[sa[i]] && y[sa[i - 1] + j] == y[sa[i] + j]) ? p - 1 : p++;
            if (p >= n) break;
            m = p;
        }
        n--;
        for (int i = 0; i <= n; i++) ra[sa[i]] = i;
        for (int i = 0, j = 0, k = 0; i <= n; i++) {
            if (k) k--;
            j = sa[ra[i] - 1];
            while (str[i + k] == str[j + k]) k++;
            height[ra[i]] = k;
        }
        st_init(height, n);
    }
    int lg[MAXN], table[23][MAXN];
    void st_init(int *arr, int n) {
        if (!lg[0]) {
            lg[0] = -1;
            for (int i = 1; i < MAXN; i++)
                lg[i] = lg[i / 2] + 1;
        }
        for (int i = 1; i <= n; ++i)
            table[0][i] = arr[i];
        for (int i = 1; i <= lg[n]; ++i)
            for (int j = 1; j <= n; ++j)
                if (j + (1 << i) - 1 <= n)
                    table[i][j] = min(table[i - 1][j], table[i - 1][j + (1 << (i - 1))]);
    }
    int lcp(int l, int r) {
        l = ra[l], r = ra[r];
        if (l > r) swap(l, r);
        ++l;
        int t = lg[r - l + 1];
        return min(table[t][l], table[t][r - (1 << t) + 1]);
    }
} sa;

/*bool cmp(int i, int j) {
    if (dis[i] != dis[j]) return dis[i] < dis[j];
    if (i + dis[i] > n) return true;
    if (j + dis[j] > n) return false;
    int lcp = sa.lcp(i + dis[i], j + dis[j]);
    return a[i + lcp + dis[i]] < a[j + lcp + dis[j]];
}*/

int main(){
    while(scanf("%d",&n)!=-1)
    {
        scanf("%s",S);
        last[0]=last[1]=0;
        s[n]=n+1;
        for (int i=n-1;i>=0;i--)
        {
            int now= S[i]=='a' ? 0 : 1;
            if (last[now]==0) s[i]=n;
            else s[i]=(last[now]-i);
            last[now]=i;
        }
        n++;
        sa.build(s,n,n+2);
        for(int i = n-1;i >=1 ;i--)
            printf("%d ",sa.sa[i]+1);
        printf("\n");
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值