$$ \newcommand{\seq}[2]{{#1}_{1},{#1}_{2},\cdots,{#1}_{#2}} \newcommand{\num}[1]{1,2,\cdots,#1} \newcommand{\stra}[2]{\begin{bmatrix}#1 \\ #2\end{bmatrix}} \newcommand{\strb}[2]{\begin{Bmatrix}#1 \\ #2\end{Bmatrix}} \newcommand{\dw}[1]{\underline{#1}} \newcommand{\up}[1]{\overline{#1}} $$

Templates

Game theory

Nim

#include<bits/stdc++.h>
using namespace std;
int main(){
	int T;
	scanf("%d",&T);
	while(T--){
		int n,x,res=0;
		scanf("%d",&n);
		while(n--){
			scanf("%d",&x);
			res^=x;
		}
		puts(res==0?"No":"Yes");
	}
	return 0;
}

SG function


Graph theory

SPFA

void spfa(int start){
	for(int i=1;i<=n;i++)dis[i]=INF,vis[i]=0;
	dis[start]=0;
	q[qhead=qtail=1]=start;
	while(qhead<=qtail){
		int u=q[qhead++];
		vis[u]=0;
		for(int i=head[u];i;i=e[i].next){
			int v=e[i].to;
			if(dis[u]+e[i].w<dis[v]){
				dis[v]=dis[u]+e[i].w;
				if(!vis[v]){
					vis[v]=1;
					q[++qtail]=v;
				}
			}
		}
	}
}

SPFA check negative cycles

void spfa(){
    for(int i=1;i<=n;i++)cnt[i]=vis[i]=0,dis[i]=INF;
    dis[1]=0;
    queue<int> q;
    q.push(1);
    while(!q.empty()){
        int u=q.top();
        q.pop();
        vis[u]=0;
        for(int i=head[u];i;i=e[i].next){
            int v=e[i].to,w=e[i].w;
            D w=e[i].a*dis[u]+e[i].b;
            if(dis[u]+w<dis[v]&&cnt[v]<=n){
                dis[v]=w;
                if(++cnt[v]>n)dis[v]=-INF;
                if(!vis[v]){
                    vis[v]=1;
                    q.push(v);
                }
            }
        }
    }
}

Dijkstra

void dijkstra(int st){
	for(int i=1;i<=n;i++){
		dis[i]=INF;
		vis[i]=0;
	}
	dis[st]=0;
	priority_queue<P,vector<P>,greater<P> > q;
	q.push(P(0,st));
	while(!q.empty()){
		int u=q.top().second,v;
		q.pop();
		if(vis[u])continue;
		vis[u]=1;
		for(int i=head[u];i;i=e[i].next){
			v=e[i].to;
			if(dis[u]+e[i].w<dis[v]&&!vis[v]){
				dis[v]=dis[u]+e[i].w;
				q.push(P(dis[v],v));
			}
		}
	}
}

Floyd

for(int k=1;k<=n;k++){
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
        }
    }
}

Floyd求路径最值限制问题

例:过路费

有一天你来到了一个奇怪的国家,它有 \(N\) 个城市,城市之间有若干条双向道路连接,每条道路都有一定的费用,经过城市也要一定的费用。从一个城市到达另一个城市的总花费为路径上费用最大的城市费用(包括起点和终点)加上路径上所有的道路的费用。给出 \(Q\) 次询问,分别回答每次询问中两城市间的最少花费。保证城市之间可以互达。

#include<bits/stdc++.h>
using namespace std;
const int maxn=303,INF=0x3f3f3f3f;
int n,m,Q,p[maxn],a[maxn],g[maxn][maxn],dp[maxn][maxn];
bool cmp(int x,int y){return a[x]<a[y];}
void floyd(int k){
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            g[i][j]=min(g[i][j],g[i][k]+g[k][j]);
        }
    }
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)scanf("%d",a+i);
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++)dp[i][j]=g[i][j]=INF;
        g[i][i]=0;
        p[i]=i;
    }
    sort(p+1,p+n+1,cmp);
    for(int i=1;i<=m;i++){
        int u,v,w;
        scanf("%d%d%d",&u,&v,&w);
        g[u][v]=g[v][u]=min(g[u][v],w);
    }
    for(int l=1,r=1;l<=n;l=r){
        for(;r<=n&&a[p[l]]==a[p[r]];r++){
            floyd(p[r]);
        }
        for(int _i=1;_i<r;_i++){
            int i=p[_i];
            for(int _j=1;_j<r;_j++){
                int j=p[_j];
                dp[i][j]=min(dp[i][j],g[i][j]+a[p[l]]);
            }
        }
    }
    scanf("%d",&Q);
    while(Q--){
        int x,y;
        scanf("%d%d",&x,&y);
        printf("%d\n",dp[x][y]);
    }
    return 0;
}

SCC

void tarjan(int u){
    dfn[u]=low[u]=++cntdfn;
    stk[++top]=u;
    for(int i=head[u];~i;i=e[i].next){
        int v=e[i].to;
        if(!dfn[v]){
            tarjan(v);
            low[u]=min(low[u],low[v]);
        }
        else if(!incyc[v]){
            low[u]=min(low[u],dfn[v]);
        }
    }
    if(dfn[u]==low[u]){
        numcyc[++cntcyc]=0;
        int x;
        do{
            x=stk[top];
            top--;
            numcyc[cntcyc]++;
            incyc[x]=cntcyc;
        }while(x!=u);
    }
}
void getcyc(){
    for(int i=1;i<=n;i++){
        if(!dfn[i])tarjan(i);
    }
}

topological-sort

void topsort(){
	queue<int> q;
	for(int i=1;i<=n;i++){
		if(indeg[i]==0){
			q.push(i);
		}
	}
	while(!q.empty()){
		int u=q.front();
		q.pop();
		for(int i=head[u];i;i=e[i].next){
			int v=e[i].to;
			if(--indeg[v]==0){
				q.push(v);
			}
		}
	}
}

bipartite-graph max-match (Hungary algorithm)

bool dfs(int u){
    for(int i=0;i<int(g[u].size());i++){
        int v=g[u][i];
        if(vis[v])continue;
        vis[v]=1;
        if(!c[v]||dfs(c[v])){
        	d[u]=v;
            c[v]=u;
            return 1;
        }
    }
    return 0;
}
int match(){
    int ret=0;
    for(int i=1;i<=n1;i++){
        for(int j=1;j<=n2;j++)vis[j]=0;
        if(dfs(i))ret++;
    }
    return ret;
}
int main(){
    scanf("%d%d%d",&n1,&n2,&m);
    for(int i=1;i<=m;i++){
        int u,v;
        scanf("%d%d",&u,&v);
        g[u].push_back(v);
    }
    printf("%d\n",match());
    return 0;
}

bipartite-graph max-match in minimum lexicographic order (Hungary algorithm)

bool dfs(int u){
    for(int i=0;i<int(g[u].size());i++){
        int v=g[u][i];
        if(vis[v])continue;
        vis[v]=1;
        if(!c[v]||dfs(c[v])){
        	d[u]=v;
            c[v]=u;
            return 1;
        }
    }
    return 0;
}
int match(){
    int ret=0;
    for(int i=n1;i>=1;i--){
        for(int j=1;j<=n2;j++)vis[j]=0;
        if(dfs(i))ret++;
    }
    return ret;
}
int main(){
    scanf("%d%d%d",&n1,&n2,&m);
    for(int i=1;i<=m;i++){
        int u,v;
        scanf("%d%d",&u,&v);
        g[u].push_back(v);
    }
    for(int i=1;i<=n1;i++)sort(g[i].begin(),g[i].end());
    printf("%d\n",match());
    return 0;
}

bipartite-graph perfect-match in maximum weight (KM-algorithm)

bool dfs(int u){
    visd[u]=1;
    for(int v=1;v<=n;v++){
        int tmp=ld[u]+lc[v]-g[u][v];
        if(!visc[v]&&!tmp){
            visc[v]=1;
            if(!c[v]||dfs(c[v])){
                c[v]=u;
                return 1;
            }
        }
        else if(tmp<slack[v]){
            slack[v]=tmp;
        }
    }
    return 0;
}
int km(){
    for(int i=1;i<=n;i++){
        c[i]=lc[i]=ld[i]=0;
        for(int j=1;j<=n;j++){
            ld[i]=max(ld[i],g[i][j]);
        }
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++)slack[j]=INF;
        while(1){
            for(int j=1;j<=n;j++)visc[j]=visd[j]=0;
            if(dfs(i))break;
            int res=INF;
            for(int v=1;v<=n;v++){
                if(!visc[v]){
                    res=min(res,slack[v]);
                }
            }
            for(int u=1;u<=n;u++){
                if(visd[u]){
                    ld[u]-=res;
                }
            }
            for(int v=1;v<=n;v++){
                if(visc[v]){
                    lc[v]+=res;
                }
                else{
                    slack[v]-=res;
                }
            }
        }
    }
    int ans=0;
    for(int i=1;i<=n;i++)ans+=ld[i]+lc[i];
    return ans;
}

network-flow (Dinic)

bool bfs(){
	for(int i=1;i<=n;i++)dep[i]=0,head1[i]=head[i];
	dep[s]=1;
	int *qhead=q,*qtail=q;
	*qtail++=s;
	while(qhead!=qtail){
		int u=*qhead++;
		for(int i=head[u];~i;i=e[i].next){
			int v=e[i].to;
			if(e[i].w&&dep[v]==0){
				dep[v]=dep[u]+1;
				*qtail++=v;
			}
		}
	}
	return dep[t]!=0;
}
int dfs(int u,int low){
	if(low==0||u==t)return low;
	int flow=0;
	for(int &i=head1[u];~i;i=e[i].next){
		int v=e[i].to;
		if(e[i].w&&dep[v]==dep[u]+1){
			int tmp=dfs(v,min(low,e[i].w));
			if(tmp==0)dep[v]=0;
			else{
				flow+=tmp;
				low-=tmp;
				e[i].w-=tmp;
				e[i^1].w+=tmp;
				if(low==0)break;
			}
		}
	}
	return flow;
}
int dinic(){
	int ans=0;
	while(bfs())ans+=dfs(s,INF);
	return ans;
}
int main(){
	int m;
	scanf("%d%d%d%d",&n,&m,&s,&t);
	for(int i=1;i<=n;i++)head[i]=-1;
	cnte=-1;
	while(m--){
		int u,v,w;
		scanf("%d%d%d",&u,&v,&w);
		addedge(u,v,w);
	}
	printf("%d",dinic());
	return 0;
}

network-flow (SPFA+EK)

bool spfa(){
	for(int i=1;i<=n;i++)flow[i]=dis[i]=INF,vis[i]=0;
	pre[t]=-1;
	dis[s]=0;
	queue<int> q;
	q.push(s);
	while(!q.empty()){
		int u=q.front();
		q.pop();
		vis[u]=0;
		for(int i=head[u];~i;i=e[i].next){
			int v=e[i].to;
			if(e[i].w>0&&dis[u]+e[i].cost<dis[v]){
				dis[v]=dis[u]+e[i].cost;
				pre[v]=u;
				edg[v]=i;
				flow[v]=min(flow[u],e[i].w);
				if(!vis[v]){
					vis[v]=1;
					q.push(v);
				}
			}
		}
	}
	return pre[t]!=-1;
}
void micmxf(){
	while(spfa()){
		int x=t;
		while(x!=s){
			e[edg[x]].w-=flow[t];
			e[edg[x]^1].w+=flow[t];
			x=pre[x];
		}
		maxflow+=flow[t];
		mincost+=flow[t]*dis[t];
	}
}
int main(){
	int m;
	scanf("%d%d%d%d",&n,&m,&s,&t);
	for(int i=0;i<=n;i++)head[i]=-1;
	cnte=-1;
	for(int i=1;i<=m;i++){
		int u,v,w,cost;
		scanf("%d%d%d%d",&u,&v,&w,&cost);
		add(u,v,w,cost);
		add(v,u,0,-cost);
	}
	micmxf();
	printf("%d %d\n",maxflow,mincost);
	return 0;
}

MST (Prim)

void prim(){
    for(int i=1;i<=n;i++)dis[i]=INT_MAX;
    priority_queue<pii,vector<pii>,greater<pii> > q;
    q.push(make_pair(0,1));
    while(!q.empty()){
        int d=q.top().first,u=q.top().second;
        q.pop();
        if(vis[u])continue;
        ans+=d;
        vis[u]=1;
        cnt++;
        for(int i=head[u];i;i=e[i].next){
            int v=e[i].to;
            if(dis[v]>e[i].w&&!vis[v]){
                dis[v]=e[i].w;
                q.push(make_pair(dis[v],v));
            }
        }
    }
}

MST (Kruskal)

void kruskal(){
    sort(e+1,e+m+1);
    ufset s(n);
    for(int i=1;i<=m;i++){
        int u=e[i].from,v=e[i].to;
        if(s.same(u,v))continue;
        ans+=e[i].w;
        s.Union(u,v);
        if(++tot==n-1)break;
    }
}

Strictly second-best MST

#include<bits/stdc++.h>
#define maxn 100003
#define maxm 300003
#define INF 100000000000000000ll
using namespace std;
typedef long long D;
D n,m,lg[maxn];
namespace G{
    struct edge{
        D from,to,w;
        bool vis;
        bool operator <(const edge& x)const{return w<x.w;}
    }e[maxm];
    D cnte;
    void add(D u,D v,D w){e[++cnte]=(edge){u,v,w,0};}
}
namespace MST{
    struct edge{
        D to,next,w;
    }e[maxn<<1];
    D head[maxn],cnte,dep[maxn],fa[maxn][23],mx[maxn][23][2];
    void add(D u,D v,D w){e[++cnte]=(edge){v,head[u],w},head[u]=cnte;}
    void calc(D &X0,D &X1,D Y0,D Y1,D Z0,D Z1){
        X0=max(Y0,Z0);
        if(Y0!=Z0)X1=max(min(Y0,Z0),max(Y1,Z1));
        else X1=max(Y1,Z1);
    }
    void init(D u,D last){
        fa[u][0]=last;
        dep[u]=dep[last]+1;
        for(D i=1;(1<<i)<=dep[u];i++){
            D up=fa[u][i-1];
            fa[u][i]=fa[up][i-1];
            calc(mx[u][i][0],mx[u][i][1],mx[u][i-1][0],mx[u][i-1][1],mx[up][i-1][0],mx[up][i-1][1]);
        }
        for(D i=head[u];i;i=e[i].next){
            D v=e[i].to;
            if(v==last)continue;
            mx[v][0][0]=e[i].w;
            init(v,u);
        }
    }
    D lca(D x,D y){
        if(dep[x]<dep[y])swap(x,y);
        while(dep[x]>dep[y]){
            x=fa[x][lg[dep[x]-dep[y]]];
        }
        if(x==y)return x;
        for(D i=lg[dep[x]];i>=0;i--){
            if(fa[x][i]!=fa[y][i]){
                x=fa[x][i];
                y=fa[y][i];
            }
        }
        return fa[x][0];
    }
    D query(D x,D y,D w){
        D l=lca(x,y);
        D ans0=0,ans1=0;
        while(x!=l){
            calc(ans0,ans1,ans0,ans1,mx[x][lg[dep[x]-dep[l]]][0],mx[x][lg[dep[x]-dep[l]]][1]);
            x=fa[x][lg[dep[x]-dep[l]]];
        }
        while(y!=l){
            calc(ans0,ans1,ans0,ans1,mx[y][lg[dep[y]-dep[l]]][0],mx[y][lg[dep[y]-dep[l]]][1]);
            y=fa[y][lg[dep[y]-dep[l]]];
        }
        if(w!=ans0)return w-ans0;
        if(ans1)return w-ans1;
        return INF;
    }
}
D f[maxn];
D find(D x){
    if(x!=f[x])f[x]=find(f[x]);
    return f[x];
}
D kruskal(){
    D cnt=0,ret=0;
    sort(G::e+1,G::e+m+1);
    for(D i=1;i<=n;i++)f[i]=i;
    for(D i=1;i<=m;i++){
        D u=G::e[i].from,v=G::e[i].to,fu=find(u),fv=find(v);
        if(fu!=fv){
            f[fu]=fv;
            ret+=G::e[i].w;
            G::e[i].vis=1;
            MST::add(u,v,G::e[i].w);
            MST::add(v,u,G::e[i].w);
            cnt++;
            if(cnt>=n)break;
        }
    }
    return ret;
}
signed main(){
    scanf("%lld%lld",&n,&m);
    for(D i=1;i<=m;i++){
        D u,v,w;
        scanf("%lld%lld%lld",&u,&v,&w);
        G::add(u,v,w);
    }
    D ans1=kruskal(),ans2=INF;
    for(D i=2;i<maxn;i++)lg[i]=lg[i-1]+((1<<(lg[i-1]+1))==i);
    MST::init(1,0);
    for(D i=1;i<=m;i++){
        if(!G::e[i].vis){
            D u=G::e[i].from,v=G::e[i].to;
            ans2=min(ans2,MST::query(u,v,G::e[i].w));
        }
    }
    printf("%lld\n",ans1+ans2);
    return 0;
}

LCA (Heavy-light decomposition)

void initdep(int u,int last){
	sz[u]=1;
	fa[u]=last;
	int mx=0;
	for(int i=head[u];i;i=e[i].next){
		int v=e[i].to;
		if(v==fa[u])continue;
		dep[v]=dep[u]+1;
		initdep(v,u);
		sz[u]+=sz[v];
		if(sz[v]>mx)mx=sz[v],son[u]=v;
	}
}
void initdfn(int u,int tp){
	dfn[u]=++cntdfn;
	num[cntdfn]=u;
	top[u]=tp;
	if(son[u]){
		initdfn(son[u],tp);
	}
	for(int i=head[u];i;i=e[i].next){
		int v=e[i].to;
		if(v==fa[u]||v==son[u])continue;
		initdfn(v,v);
	}
	rig[u]=cntdfn;
}
int lca(int x,int y){
	while(top[x]!=top[y]){
		if(dep[top[x]]<dep[top[y]])swap(x,y);
		x=fa[top[x]];
	}
	if(dep[x]<dep[y])swap(x,y);
	return y;
}

LCA (ST RMQ)

void init(int u,int last){
    st[++cntdfn][0]=u;
    dfn[u]=cntdfn;
    for(int i=head[u];i;i=e[i].next){
        int v=e[i].to;
        if(v==last)continue;
        dep[v]=dep[u]+1;
        init(v,u);
        st[++cntdfn][0]=u;
    }
}
int MIN(int x,int y){return dep[x]<dep[y]?x:y;}
void initst(){
    for(int len=1;(1<<len)<=cntdfn;len++){
        for(int i=1;i+(1<<len)-1<=cntdfn;i++){
            st[i][len]=MIN(st[i][len-1],st[i+(1<<(len-1))][len-1]);
        }
    }
}
int lca(int x,int y){
    if(dfn[x]>dfn[y])swap(x,y);
    int tmp=lg[dfn[y]-dfn[x]+1];
    return MIN(st[dfn[x]][tmp],st[dfn[y]-(1<<tmp)+1][tmp]);
}

LCA (doubling)

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

Virtual tree

例:[SDOI2011]消耗战

#include<bits/stdc++.h>
using namespace std;
const int maxn=250003,maxm=500003,INF=0x3f3f3f3f;
struct edge{int to,next,w;}e[maxn<<1];
int head[maxn],cnte;
void add(int u,int v,int w){e[++cnte].to=v,e[cnte].w=w,e[cnte].next=head[u],head[u]=cnte;}
int n,lg[maxn],fa[maxn][23],cntdfn,dfn[maxn],rig[maxn],dep[maxn],p[maxn<<2],
mi[maxn],stk[maxn],top;
long long dp[maxn];
bool vis[maxn];
void init(int u,int last){
	dfn[u]=++cntdfn;
	fa[u][0]=last;
	for(int i=1;(1<<i)<=dep[u];i++)fa[u][i]=fa[fa[u][i-1]][i-1];
	for(int i=head[u];i;i=e[i].next){
		int v=e[i].to;
		if(v==last)continue;
		dep[v]=dep[u]+1;
		mi[v]=min(mi[u],e[i].w);
		init(v,u);
	}
	rig[u]=++cntdfn;
}
int lca(int x,int y){
	if(dep[x]<dep[y])swap(x,y);
	while(dep[x]>dep[y])x=fa[x][lg[dep[x]-dep[y]]];
	if(x==y)return x;
	for(int i=lg[dep[x]];i>=0;i--)if(fa[x][i]!=fa[y][i])x=fa[x][i],y=fa[y][i];
	return fa[x][0];
}
bool cmp(int x,int y){return (x>0?dfn[x]:rig[-x])<(y>0?dfn[y]:rig[-y]);}
int main(){
	for(int i=2;i<maxn;i++)lg[i]=lg[i-1]+((1<<(lg[i-1]+1))==i);
	scanf("%d",&n);
	for(int i=1;i<n;i++){
		int u,v,w;
		scanf("%d%d%d",&u,&v,&w);
		add(u,v,w),add(v,u,w);
	}
	mi[1]=INF;
	init(1,0);
	int Q;
	scanf("%d",&Q);
	while(Q--){
		int m;
		scanf("%d",&m);
		for(int i=1;i<=m;i++)scanf("%d",p+i),vis[p[i]]=1,dp[p[i]]=mi[p[i]];
		sort(p+1,p+m+1,cmp);
		for(int i=2;i<=m;i++){
			int l=lca(p[i-1],p[i]);
			if(vis[l])continue;
			vis[l]=1;
			p[++m]=l;
		}
		for(int i=m;i>=1;i--)p[++m]=-p[i];
		if(!vis[1]){
			p[++m]=1,p[++m]=-1;
			vis[1]=1;
		}
		sort(p+1,p+m+1,cmp);
		top=0;
		for(int i=1;i<m;i++){
			if(p[i]>0){
				stk[++top]=p[i];
			}
			else{
				int u=stk[top--],last=stk[top];
				dp[last]+=min(dp[u],(long long)mi[u]);
				vis[u]=0,dp[u]=0;
			}
		}
		printf("%lld\n",dp[1]);
		vis[1]=0,dp[1]=0;
	}
	return 0;
}

Tree-plus-cycle (containing multiple edges)

bool init(int u){
	stk[++top]=u;
	instk[u]=1;
	for(int i=head[u];i;i=e[i].next){
		int id=(i+1)>>1;
		if(vis[id])continue;
		vis[id]=1;
		int v=e[i].to;
		if(instk[v]){
			int x;
			do{
				x=stk[top--];
				p[++tot]=x;
			}while(x!=v);
			return 1;
		}
		if(init(v))return 1;
	}
	top--;
	return 0;
}

Divide-and-conquer on tree

例:【模板】点分治

#include<bits/stdc++.h>
using namespace std;
const int maxn=10003,INF=0x3f3f3f3f;
struct edge{int to,next,w;}e[maxn<<1];
int head[maxn],cnte;
void add(int u,int v,int w){e[++cnte].to=v,e[cnte].w=w,e[cnte].next=head[u],head[u]=cnte;}
int n,m,k,dis[maxn],cntdis;
bool vis[maxn];
namespace GG{
	int sz[maxn],G,szG;
	int inittrsz(int u,int last){
		int trsz=1;
		for(int i=head[u];i;i=e[i].next){
			int v=e[i].to;
			if(v==last||vis[v])continue;
			trsz+=inittrsz(v,u);
		}
		return trsz;
	}
	void getG1(int u,int last,int trsz){
		int ret=0;
		sz[u]=1;
		for(int i=head[u];i;i=e[i].next){
			int v=e[i].to;
			if(v==last||vis[v])continue;
			getG1(v,u,trsz);
			ret=max(ret,sz[v]);
			sz[u]+=sz[v];
		}
		ret=max(ret,trsz-sz[u]);
		if(ret<szG){
			szG=ret;
			G=u;
		}
	}
	int getG(int u){
		int trsz=inittrsz(u,0);
		szG=INF;
		getG1(u,0,trsz);
		return G;
	}
}
void work(int u,int last,int depth){
	dis[++cntdis]=depth;
	for(int i=head[u];i;i=e[i].next){
		int v=e[i].to;
		if(v==last||vis[v])continue;
		work(v,u,depth+e[i].w);
	}
}
int solve(int u,int kk){
	cntdis=0;
	work(u,0,0);
	sort(dis+1,dis+cntdis+1);
	int ans=0;
	pair<int*,int*> tmp;
	for(int i=1;i<=cntdis;i++){
		tmp=equal_range(dis+i+1,dis+cntdis+1,kk-dis[i]);
		ans+=tmp.second-tmp.first;
	}
	return ans;
}
bool dfs(int g){
	int ans=solve(g,k);
	vis[g]=1;
	for(int i=head[g];i;i=e[i].next){
		int v=e[i].to;
		if(vis[v])continue;
		ans-=solve(v,k-(e[i].w<<1));
	}
	if(ans)return 1;
	for(int i=head[g];i;i=e[i].next){
		int v=e[i].to;
		if(vis[v])continue;
		int gg=GG::getG(v);
		if(dfs(gg))return 1;
	}
	return 0;
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<n;i++){
		int u,v,w;
		scanf("%d%d%d",&u,&v,&w);
		add(u,v,w),add(v,u,w);
	}
	int g=GG::getG(1);
	while(m--){
		scanf("%d",&k);
		for(int i=1;i<=n;i++)vis[i]=0;
		puts(dfs(g)?"AYE":"NAY");
	}
	return 0;
}

DSU on tree

例:Codeforces 600E

#include<bits/stdc++.h>
using namespace std;
const int maxn=100003;
struct edge{int to,next;}e[maxn<<1];
int head[maxn],cnte;
void add(int u,int v){e[++cnte].to=v,e[cnte].next=head[u],head[u]=cnte;}
int n,a[maxn],sz[maxn],son[maxn],buc[maxn],mxcnt;
long long sum,ANS[maxn];
void init(int u,int last){
	sz[u]=1;
	int res=0;
	for(int i=head[u];i;i=e[i].next){
		int v=e[i].to;
		if(v==last)continue;
		init(v,u);
		sz[u]+=sz[v];
		if(sz[v]>res)res=sz[v],son[u]=v;
	}
}
void add(int u,int last,int heavy){
	buc[a[u]]++;
	if(buc[a[u]]>mxcnt)mxcnt=buc[a[u]],sum=a[u];
	else if(buc[a[u]]==mxcnt)sum+=a[u];
	for(int i=head[u];i;i=e[i].next){
		int v=e[i].to;
		if(v==last||v==heavy)continue;
		add(v,u,heavy);
	}
}
void del(int u,int last){
	buc[a[u]]--;
	for(int i=head[u];i;i=e[i].next){
		int v=e[i].to;
		if(v==last)continue;
		del(v,u);
	}
}
void dfs(int u,int last,bool keep){
	for(int i=head[u];i;i=e[i].next){
		int v=e[i].to;
		if(v==last||v==son[u])continue;
		dfs(v,u,0);
	}
	if(son[u])dfs(son[u],u,1);
	add(u,last,son[u]);
	ANS[u]=sum;
	if(!keep){
		mxcnt=sum=0;
		del(u,last);
	}
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++)scanf("%d",a+i);
	for(int i=1;i<n;i++){
		int u,v;
		scanf("%d%d",&u,&v);
		add(u,v),add(v,u);
	}
	init(1,0);
	dfs(1,0,0);
	for(int i=1;i<=n;i++)printf("%lld ",ANS[i]);
	return 0;
}

Data structures

Heavy-light-decomposition

namespace SEG{
    struct node{
        long long sum,z;
    }t[maxn<<2];
    void pushdown(int p,int l,int r){
        if(l==r){t[p].z=0;return;}
        if(t[p].z){
            int mid=(l+r)>>1;
            PlusEqual(t[p<<1].sum,L(t[p].z*(mid-l+1)));
            PlusEqual(t[p<<1|1].sum,L(t[p].z*(r-mid)));
            PlusEqual(t[p<<1].z,t[p].z);
            PlusEqual(t[p<<1|1].z,t[p].z);
            t[p].z=0;
        }
    }
    void pushup(int p,int l,int r){
        t[p].sum=L(t[p<<1].sum+t[p<<1|1].sum);
    }
    void build(int p,int l,int r){
        t[p].z=0;
        if(l==r){
            t[p].sum=a[num[l]];
            return;
        }
        int mid=(l+r)>>1;
        build(p<<1,l,mid);
        build(p<<1|1,mid+1,r);
        pushup(p,l,r);
    }
    void change(int p,int l,int r,int pos,long long k){
        pushdown(p,l,r);
        if(l==r){
            PlusEqual(t[p].sum,k);
            return;
        }
        int mid=(l+r)>>1;
        if(pos<=mid)change(p<<1,l,mid,pos,k);
        else change(p<<1|1,mid+1,r,pos,k);
        pushup(p,l,r);
    }
    void change(int p,int l,int r,int seg_l,int seg_r,long long k){
        pushdown(p,l,r);
        if(seg_l<=l&&r<=seg_r){
            PlusEqual(t[p].sum,L(k*(r-l+1)));
            t[p].z=k;
            return;
        }
        int mid=(l+r)>>1;
        if(seg_l<=mid)change(p<<1,l,mid,seg_l,seg_r,k);
        if(seg_r>mid)change(p<<1|1,mid+1,r,seg_l,seg_r,k);
        pushup(p,l,r);
    }
    long long query(int p,int l,int r,int seg_l,int seg_r){
        pushdown(p,l,r);
        if(seg_l<=l&&r<=seg_r){
            return t[p].sum;
        }
        int mid=(l+r)>>1;
        long long ret=0;
        if(seg_l<=mid)PlusEqual(ret,query(p<<1,l,mid,seg_l,seg_r));
        if(seg_r>mid)PlusEqual(ret,query(p<<1|1,mid+1,r,seg_l,seg_r));
        return ret;
    }
}

void initdep(int u,int last,int depth){
    fa[u]=last;
    dep[u]=depth;
    sz[u]=1;
    int mxsz=0;
    for(int i=head[u];~i;i=e[i].next){
        int v=e[i].to;
        if(v==fa[u])continue;
        initdep(v,u,depth+1);
        sz[u]+=sz[v];
        if(sz[v]>mxsz)mxsz=sz[v],son[u]=v;
    }
}
void initdfn(int u,int tp){
    dfn[u]=++cntdfn;
    num[cntdfn]=u;
    top[u]=tp;
    if(son[u]){
        initdfn(son[u],tp);
        for(int i=head[u];~i;i=e[i].next){
            int v=e[i].to;
            if(v==fa[u]||v==son[u])continue;
            initdfn(v,v);
        }
    }
    rig[u]=cntdfn;
}
void change(int u,long long w){
    SEG::change(1,1,n,dfn[u],w);
}
void change(int x,int y,long long w){
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        SEG::change(1,1,n,dfn[top[x]],dfn[x],w);
        x=fa[top[x]];
    }
    if(dep[x]<dep[y])swap(x,y);
    SEG::change(1,1,n,dfn[y],dfn[x],w);
}
void changesub(int u,long long w){
    SEG::change(1,1,n,dfn[u],rig[u],w);
}
long long query(int x,int y){
    long long ans=0;
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        PlusEqual(ans,SEG::query(1,1,n,dfn[top[x]],dfn[x]));
        x=fa[top[x]];
    }
    if(dep[x]<dep[y])swap(x,y);
    PlusEqual(ans,SEG::query(1,1,n,dfn[y],dfn[x]));
    return ans;
}
long long querysub(int x){
    return SEG::query(1,1,n,dfn[x],rig[x]);
}

LCT

例:QTREE

#include<stdio.h>
#define maxn 20003
void swap(int *x,int *y){int t=*x;*x=*y;*y=t;}
int max(int x,int y){return x>y?x:y;}

struct node{
    int val,mx,fa,son[2],z;
}t[maxn];
int isroot(int p){return t[t[p].fa].son[0]!=p&&t[t[p].fa].son[1]!=p;}
int chk(int p){return t[t[p].fa].son[1]==p;}
void reverse(int p){if(p==0)return;swap(&t[p].son[0],&t[p].son[1]);t[p].z^=1;}
void pushup(int p){t[p].mx=max(max(t[t[p].son[0]].mx,t[t[p].son[1]].mx),t[p].val);}
void pushdown(int p){
    if(t[p].z){
        reverse(t[p].son[0]);
        reverse(t[p].son[1]);
        t[p].z=0;
    }
}
void pushall(int p){if(!isroot(p))pushall(t[p].fa);pushdown(p);}
void rotate(int p){
    int q=t[p].fa,r=t[q].fa,k=chk(p),s=t[p].son[!k];
    t[q].son[k]=s,t[s].fa=q;
    if(!isroot(q))t[r].son[chk(q)]=p;
    t[p].fa=r;
    t[p].son[!k]=q,t[q].fa=p;
    pushup(q);
    pushup(p);
}
void splay(int p){
    pushall(p);
    while(!isroot(p)){
        int q=t[p].fa;
        if(!isroot(q)){
            if(chk(p)==chk(q))rotate(q);
            else rotate(p);
        }
        rotate(p);
    }
}
void new_node(int p,int fa,int k){t[p].fa=fa,t[p].mx=t[p].val=k;}

void access(int x){for(int y=0;x;y=x,x=t[x].fa)splay(x),t[x].son[1]=y,pushup(x);}
void change(int x,int k){splay(x),t[x].val=k,pushup(x);}
void makeroot(int x){access(x),splay(x),reverse(x);}
int query(int x,int y){makeroot(x),access(y),splay(y);return t[y].mx;}

struct edge{int to,next;}e[maxn<<1];
int head[maxn],cnte;
void add(int u,int v){e[++cnte].to=v,e[cnte].next=head[u],head[u]=cnte;}
int n,a[maxn],ed[maxn];
void dfs(int u,int last){
    new_node(u,last,a[u]);
    for(int i=head[u];i;i=e[i].next){
        int v=e[i].to;
        if(v==last)continue;
        dfs(v,u);
    }
}
void init(){
    for(int i=0;i<=(n<<1);i++)t[i].val=t[i].mx=t[i].fa=t[i].son[0]=t[i].son[1]=t[i].z=head[i]=a[i]=ed[i]=0;
    cnte=0;
}
char mo[13];
int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        scanf("%d",&n);
        init();
        for(int i=1;i<n;i++){
            int u,v,w;
            scanf("%d",&u),scanf("%d",&v),scanf("%d",&w);
            add(u,i+n),add(i+n,u),add(i+n,v),add(v,i+n);
            ed[i]=i+n;
            a[i+n]=w;
        }
        n=n+n-1;
        dfs(1,0);
        while(scanf("%s",mo),*mo!='D'){
            int x,y;
            scanf("%d",&x),scanf("%d",&y);
            if(*mo=='Q'){
                printf("%d\n",query(x,y));
            }
            else{
                change(ed[x],y);
            }
        }
    }
    return 0;
}

QTREE7

#include<bits/stdc++.h>
using namespace std;
const int maxn=100003,INF=0x3f3f3f3f;
template<typename tp>
void read(tp& x){
	x=0;
	char c=getchar();
	bool sgn=0;
	while((c<'0'||c>'9')&&c!='-')c=getchar();
	if(c=='-')sgn=1,c=getchar();
	while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+c-'0',c=getchar();
	if(sgn)x=-x;
}
template<typename tp>
void write(tp x){
	if(x<0)putchar('-'),write(-x);
	else{
		if(x>=10)write(x/10);
		putchar(x%10+'0');
	}
}

struct edge{int to,next;}e[maxn<<1];
int head[maxn],cnte;
void add(int u,int v){e[++cnte].to=v,e[cnte].next=head[u],head[u]=cnte;}
int n,fa[maxn],val[maxn],a[maxn];

struct LCT{
	struct node{
		int mx,fa,son[2];
	};node t[maxn];
	multiset<int,greater<int> > light[maxn];
	bool isroot(int p){return t[t[p].fa].son[0]!=p&&t[t[p].fa].son[1]!=p;}
	bool chk(int p){return t[t[p].fa].son[1]==p;}
	void pushup(int p){
		t[p].mx=max(max(max(t[t[p].son[0]].mx,t[t[p].son[1]].mx),a[p]),light[p].empty()?-INF:*light[p].begin());
	}
	void rotate(int p){
		int q=t[p].fa,r=t[q].fa,k=chk(p),s=t[p].son[!k];
		t[q].son[k]=s,t[s].fa=q;
		if(!isroot(q))t[r].son[chk(q)]=p;
		t[p].fa=r;
		t[p].son[!k]=q,t[q].fa=p;
		pushup(q);
		pushup(p);
	}
	void splay(int p){
		while(!isroot(p)){
			int q=t[p].fa,r=t[q].fa;
			if(!isroot(q)){
				if(chk(p)==chk(q))rotate(q);
				else rotate(p);
			}
			rotate(p);
		}
	}
	int find(int p){
		while(t[p].son[0])p=t[p].son[0];
		splay(p);
		return p;
	}

	void access(int x){
		for(int y=0;x;y=x,x=t[x].fa){
			splay(x);
			light[x].insert(t[t[x].son[1]].mx);
			t[x].son[1]=y;
			light[x].erase(light[x].lower_bound(t[t[x].son[1]].mx));
			pushup(x);
		}
	}
	void link(int x){
		if(fa[x]==0)return;
		access(fa[x]),splay(fa[x]),splay(x);
		t[x].fa=fa[x];
		light[fa[x]].insert(t[x].mx);
		pushup(fa[x]);
	}
	void cut(int x){
		if(fa[x]==0)return;
		access(x),splay(x);
		t[x].son[0]=t[t[x].son[0]].fa=0;
		pushup(x);
	}
	int query(int x){
		access(x),splay(x);
		int tmp=find(x);
		return val[tmp]==val[x]?t[tmp].mx:t[t[tmp].son[1]].mx;
	}

	void init(int n){for(int i=0;i<=n;i++)t[i].mx=-INF,t[i].fa=t[i].son[0]=t[i].son[1]=0;}
}tree[2];

void dfs(int u,int last){
	fa[u]=last;
	for(int i=head[u];i;i=e[i].next){
		int v=e[i].to;
		if(v==last)continue;
		dfs(v,u);
	}
}

int main(){
	read(n);
	tree[0].init(n);
	tree[1].init(n);
	for(int i=0;i<=n;i++)a[i]=-INF;
	for(int i=1;i<n;i++){
		int u,v;
		read(u),read(v);
		add(u,v),add(v,u);
	}
	for(int i=1;i<=n;i++)read(val[i]);
	for(int i=1;i<=n;i++)read(a[i]),tree[0].t[i].mx=tree[1].t[i].mx=a[i];
	dfs(1,0);
	for(int i=1;i<=n;i++)tree[val[i]].link(i);
	int Q;
	read(Q);
	while(Q--){
		int mo,x;
		read(mo),read(x);
		if(mo==1){
			tree[val[x]].cut(x);
			val[x]^=1;
			tree[val[x]].link(x);
		}
		else if(mo==2){
			int y;
			read(y);
			tree[0].access(x),tree[0].splay(x),tree[1].access(x),tree[1].splay(x);
			a[x]=y;
			tree[0].pushup(x),tree[1].pushup(x);
		}
		else{
			write(tree[val[x]].query(x)),putchar('\n');
		}
	}
	return 0;
}

【模板】动态树

#include<bits/stdc++.h>
using namespace std;
const int maxn=300003;
template<typename tp>
void read(tp& x){
    x=0;
    char c=getchar();
    bool sgn=0;
    while((c<'0'||c>'9')&&c!='-')c=getchar();
    if(c=='-')sgn=1,c=getchar();
    while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+c-'0',c=getchar();
    if(sgn)x=-x;
}
template<typename tp>
void write(tp x){
    if(x<0)putchar('-'),write(-x);
    else{
        if(x>=10)write(x/10);
        putchar(x%10+'0');
    }
}

int n,a[maxn];

struct node{
    int sum,fa,son[2];
    bool z;
}t[maxn];
bool isroot(int p){return t[t[p].fa].son[0]!=p&&t[t[p].fa].son[1]!=p;}
bool chk(int p){return t[t[p].fa].son[1]==p;}
void reverse(int p){if(p==0)return;swap(t[p].son[0],t[p].son[1]);t[p].z^=1;}
void pushup(int p){
    t[p].sum=t[t[p].son[0]].sum^t[t[p].son[1]].sum^a[p];
}
void pushdown(int p){
    if(t[p].z){
        reverse(t[p].son[0]);
        reverse(t[p].son[1]);
        t[p].z=0;
    }
}
void pushall(int p){if(!isroot(p))pushall(t[p].fa);pushdown(p);}
void rotate(int p){
    int q=t[p].fa,r=t[q].fa,k=chk(p),s=t[p].son[!k];
    t[q].son[k]=s,t[s].fa=q;
    if(!isroot(q))t[r].son[chk(q)]=p;
    t[p].fa=r;
    t[p].son[!k]=q,t[q].fa=p;
    pushup(q);
    pushup(p);
}
void splay(int p){
    pushall(p);
    while(!isroot(p)){
        int q=t[p].fa;
        if(!isroot(q)){
            if(chk(p)==chk(q))rotate(q);
            else rotate(p);
        }
        rotate(p);
    }
}

void access(int x){for(int y=0;x;y=x,x=t[x].fa)splay(x),t[x].son[1]=y,pushup(x);}
void change(int x,int k){splay(x),a[x]=k,pushup(x);}
void makeroot(int x){access(x),splay(x),reverse(x);}
int findroot(int x){
    access(x),splay(x);
    while(t[x].son[0])pushdown(x),x=t[x].son[0];
    splay(x);
    return x;
}
int query(int x,int y){makeroot(x),access(y),splay(y);return t[y].sum;}
bool link(int x,int y){
    makeroot(x);
    if(findroot(y)==x)return 0;
    t[x].fa=y;
    return 1;
}
bool cut(int x,int y){
    makeroot(x);
    if(findroot(y)!=x||t[y].fa!=x||t[y].son[0])return 0;
    t[y].fa=t[x].son[1]=0;
    pushup(x);
    return 1;
}

int main(){
    int Q;
    read(n),read(Q);
    for(int i=1;i<=n;i++)read(a[i]),t[i].sum=a[i];
    while(Q--){
        int mo,x,y;
        read(mo),read(x),read(y);
        if(mo==0){
            write(query(x,y)),putchar('\n');
        }
        else if(mo==1){
            link(x,y);
        }
        else if(mo==2){
            cut(x,y);
        }
        else{
            change(x,y);
        }
    }
    return 0;
}

单调队列

#include<bits/stdc++.h>
using namespace std;
const int maxn=1000003;
int a[maxn],n,k,q[maxn],qhead,qtail;
int main(){
	scanf("%d%d",&n,&k);
	for(int i=1;i<=n;i++)scanf("%d",a+i);
	qhead=1,qtail=0;
	for(int i=1;i<=n;i++){
		while(qhead<=qtail&&a[i]<=a[q[qtail]])qtail--;
		q[++qtail]=i;
		while(qhead<=qtail&&i-q[qhead]>=k)qhead++;
		if(i>=k)printf("%d ",a[q[qhead]]);
	}
	puts("");
	qhead=1,qtail=0;
	for(int i=1;i<=n;i++){
		while(qhead<=qtail&&a[i]>=a[q[qtail]])qtail--;
		q[++qtail]=i;
		while(qhead<=qtail&&i-q[qhead]>=k)qhead++;
		if(i>=k)printf("%d ",a[q[qhead]]);
	}
	return 0;
}

Heap

template<typename tp>
class heap{
	tp h[1000002];
    int cnt;
	public:
	heap():cnt(0){}
	void push(const tp &x){
		h[++cnt]=x;
		int p=cnt;
		while(p>=2&&h[p>>1]>h[p]){
			swap(h[p>>1],h[p]);
			p>>=1;
		}
	}
	void pop(){
		swap(h[1],h[cnt]);
		cnt--;
		int p=1;
		while((p<<1)<=cnt){
			p<<=1;
			if(p<cnt&&h[p|1]<h[p])p|=1;
			if(h[p]<h[p>>1])swap(h[p],h[p>>1]);
			else break;
		}
	}
	const tp &top(){
		return h[1];
	}
};

单调栈

for(int i=1;i<=n;i++){
    int top=0;
    for(int j=1;j<=n;j++){
        if(b[i][j])a[j]=i;
        int tot=1;
        while(top&&a[j]>=a[stk[top]]){
            D tmp=at(a[stk[top]]+1,stk[top]-cnt[top]+1,i,j-1);
            if(tmp>ans){
                ans=tmp;
                x1=a[stk[top]]+1,y1=stk[top]-cnt[top]+1,x2=i,y2=j-1;
            }
            tot+=cnt[top];
            top--;
        }
        stk[++top]=j;
        cnt[top]=tot;
    }
    while(top){
        D tmp=at(a[stk[top]]+1,stk[top]-cnt[top]+1,i,n);
        if(tmp>ans){
            ans=tmp;
            x1=a[stk[top]]+1,y1=stk[top]-cnt[top]+1,x2=i,y2=n;
        }
        top--;
    }
}

左偏树

int new_node(int val){
	t[++cnt].val=val;
	return cnt;
}
void merge(int &p,int x,int y){
	if(x==0||y==0){p=x+y;return;}
	if(a[t[x].val]!=a[t[y].val]?a[t[x].val]>a[t[y].val]:t[x].val>t[y].val)swap(x,y);
	p=x;
	merge(R(p),R(x),y);
	if(dis[L(p)]<dis[R(p)])swap(L(p),R(p));
	dis[p]=dis[R(p)]+1;
}
void pop(int &p){
	merge(p,L(p),R(p));
}

DSU

int f[maxn];
int find(int x){return x!=f[x]?f[x]=find(f[x]):x;}
void Union(int x,int y){int fx=find(x),fy=find(y);if(fx!=fy)f[fx]=fy;}
bool same(int x,int y){return find(x)==find(y);}

ST algorithm

void init(){
	for(int i=1;i<=n;i++)lg[i]=lg[i>>1]+1;
	for(int len=1;(1<<len)<=n;len++){
		for(int i=1;i+(1<<len)-1<=n;i++){
			st[i][len]=max(st[i][len-1],st[i+(1<<(len-1))][len-1]);
		}
	}
}
int query(int l,int r){
	int tmp=lg[r-l+1];
	return max(st[l][tmp],st[r-(1<<tmp)+1]fe[tmp]);
}

Fenwick tree

int t[maxn];
void add(int pos,int k){while(pos<=n)t[pos]+=k,pos+=pos&-pos;}
int query(int pos){int ret=0;while(pos)ret+=t[pos],pos-=pos&-pos;return ret;}

Segment tree

merge

void merge(int &p,int q){
	if(!p||!q){p|=q;return;}
    cnt++;
    sz[cnt]=sz[p]+sz[q];
    p=cnt;
	merge(L[p],L[q]);
	merge(R[p],R[q]);
}

树套树

#include<bits/stdc++.h>
#define L(p) t[p].son[0]
#define R(p) t[p].son[1]
using namespace std;
const int maxn=100005,maxv=100000000,INF=2147483647;
struct treap_node{
	int val,son[2],sz;
}t[4000005];
int cnt,n,a[maxn];
struct TREAP{
	int root;
	TREAP():root(0){}
	void O(int p){
		if(p==0)return;
		O(L(p));
		printf("%d ",t[p].val);
		O(R(p));
	}
	void DEBUG(){
		printf("###### DEBUG root:%d ######\n",root);
		O(root);
		printf("\n######  ######\n");
	}
	void pushup(int p){t[p].sz=t[L(p)].sz+t[R(p)].sz+1;}
	void split(int p,int k,int &x,int &y){
		if(p==0){x=y=0;return;}
		if(t[p].val<=k){
			x=p;
			split(R(p),k,R(p),y);
		}
		else{
			y=p;
			split(L(p),k,x,L(p));
		}
		pushup(p);
	}
	void merge(int &p,int x,int y){
		if(x==0||y==0){p=x+y;return;}
		if(rand()%(t[x].sz+t[y].sz)<t[x].sz){
			merge(R(x),R(x),y);
			pushup(x);
			p=x;
		}
		else{
			merge(L(y),x,L(y));
			pushup(y);
			p=y;
		}
	}
	int new_node(int k){
		cnt++;
		t[cnt].val=k;
		t[cnt].sz=1;
		return cnt;
	}
	void insert(int k){
		int p,x,y;
		split(root,k,x,y);
		p=new_node(k);
		merge(p,x,p);
		merge(root,p,y);
	}
	void erase(int k){
		int x,y,z;
		split(root,k,x,y);
		split(x,k-1,z,x);
		merge(z,z,L(x));
		merge(y,R(x),y);
		merge(root,z,y);
	}
	int rnk(int k){
		int x,y;
		split(root,k-1,x,y);
		int ret=t[x].sz+1;
		merge(root,x,y);
		return ret;
	}
	int kth(int p,int k){
		while(1){
			if(k<=t[L(p)].sz)p=L(p);
			else{
				k-=(t[L(p)].sz+1);
				if(k<=0)return p;
				p=R(p);
			}
		}
	}
	int pre(int k){
		int x,y;
		split(root,k-1,x,y);
		if(t[x].sz==0)return -INF;
		int ret=kth(x,t[x].sz);
		merge(root,x,y);
		return t[ret].val;
	}
	int nxt(int k){
		int x,y;
		split(root,k,x,y);
		if(t[y].sz==0)return INF;
		int ret=kth(y,1);
		merge(root,x,y);
		return t[ret].val;
	}
};
struct SEG{
	struct seg_node{
		TREAP tr;
	}t[maxn<<2];
	void build(int p,int l,int r){
		for(int i=l;i<=r;i++)t[p].tr.insert(a[i]);
		if(l==r)return;
		int mid=(l+r)>>1;
		build(p<<1,l,mid);
		build(p<<1|1,mid+1,r);
	}
	void change(int p,int l,int r,int pos,int k){
		t[p].tr.erase(a[pos]);
		t[p].tr.insert(k);
		if(l==r)return;
		int mid=(l+r)>>1;
		if(pos<=mid)change(p<<1,l,mid,pos,k);
		else change(p<<1|1,mid+1,r,pos,k);
	}
	int _rnk(int p,int l,int r,int seg_l,int seg_r,int k){
		if(seg_l<=l&&r<=seg_r)return t[p].tr.rnk(k)-1;
		int mid=(l+r)>>1,ret=0;
		if(seg_l<=mid)ret+=_rnk(p<<1,l,mid,seg_l,seg_r,k);
		if(seg_r>mid)ret+=_rnk(p<<1|1,mid+1,r,seg_l,seg_r,k);
		return ret;
	}
	int rnk(int seg_l,int seg_r,int k){
		return _rnk(1,1,n,seg_l,seg_r,k)+1;
	}
	int kth(int seg_l,int seg_r,int k){
		int l=0,r=maxv,mid,ans=-1;
		while(l<=r){
			mid=(l+r)>>1;
			if(rnk(seg_l,seg_r,mid)<=k)ans=mid,l=mid+1;
			else r=mid-1;
		}
		return ans;
	}
	int pre(int p,int l,int r,int seg_l,int seg_r,int k){
		if(seg_l<=l&&r<=seg_r)return t[p].tr.pre(k);
		int mid=(l+r)>>1,ret=-INF;
		if(seg_l<=mid)ret=max(ret,pre(p<<1,l,mid,seg_l,seg_r,k));
		if(seg_r>mid)ret=max(ret,pre(p<<1|1,mid+1,r,seg_l,seg_r,k));
		return ret;
	}
	int nxt(int p,int l,int r,int seg_l,int seg_r,int k){
		if(seg_l<=l&&r<=seg_r)return t[p].tr.nxt(k);
		int mid=(l+r)>>1,ret=INF;
		if(seg_l<=mid)ret=min(ret,nxt(p<<1,l,mid,seg_l,seg_r,k));
		if(seg_r>mid)ret=min(ret,nxt(p<<1|1,mid+1,r,seg_l,seg_r,k));
		return ret;
	}
}seg;
int main(){
	srand(19260817);
	int Q,mo,x,y,z;
	scanf("%d%d",&n,&Q);
	for(int i=1;i<=n;i++)scanf("%d",a+i);
	seg.build(1,1,n);
	while(Q--){
		scanf("%d%d%d",&mo,&x,&y);
		switch(mo){
			case 1:scanf("%d",&z),printf("%d\n",seg.rnk(x,y,z));break;
			case 2:scanf("%d",&z),printf("%d\n",seg.kth(x,y,z));break;
			case 3:seg.change(1,1,n,x,y),a[x]=y;break;
			case 4:scanf("%d",&z),printf("%d\n",seg.pre(1,1,n,x,y,z));break;
			case 5:scanf("%d",&z),printf("%d\n",seg.nxt(1,1,n,x,y,z));break;
		}
	}
	return 0;
}

Treap

维护权值

#include<bits/stdc++.h>
#define maxn 100003
using namespace std;
struct node{
	int val,son[2],sz;
}t[maxn];
int cnt,root;
void pushup(int p){t[p].sz=t[t[p].son[0]].sz+t[t[p].son[1]].sz+1;}
void split(int p,int k,int &x,int &y){
	if(p==0){x=y=0;return;}
	if(t[p].val<=k){
		x=p;
		split(t[p].son[1],k,t[p].son[1],y);
	}
	else{
		y=p;
		split(t[p].son[0],k,x,t[p].son[0]);
	}
	pushup(p);
}
void merge(int &p,int x,int y){
	if(x==0||y==0){p=x+y;return;}
	if(rand()%(t[x].sz+t[y].sz)<t[x].sz){
		merge(t[x].son[1],t[x].son[1],y);
		pushup(x);
		p=x;
	}
	else{
		merge(t[y].son[0],x,t[y].son[0]);
		pushup(y);
		p=y;
	}
}
int new_node(int k){
	cnt++;
	t[cnt].val=k;
	t[cnt].sz=1;
	return cnt;
}
void insert(int k){
	int p,x,y;
	split(root,k,x,y);
	p=new_node(k);
	merge(p,x,p);
	merge(root,p,y);
}
void erase(int k){
	int x,y,z;
	split(root,k,x,y);
	split(x,k-1,z,x);
	merge(z,z,t[x].son[0]);
	merge(y,t[x].son[1],y);
	merge(root,z,y);
}
int rnk(int k){
	int x,y;
	split(root,k-1,x,y);
	int ret=t[x].sz+1;
	merge(root,x,y);
	return ret;
}
int kth(int p,int k){
	while(1){
		if(k<=t[t[p].son[0]].sz)p=t[p].son[0];
		else{
			k-=(t[t[p].son[0]].sz+1);
			if(k<=0)return p;
			p=t[p].son[1];
		}
	}
}
int pre(int k){
	int x,y;
	split(root,k-1,x,y);
	int ret=kth(x,t[x].sz);
	merge(root,x,y);
	return ret;
}
int nxt(int k){
	int x,y;
	split(root,k,x,y);
	int ret=kth(y,1);
	merge(root,x,y);
	return ret;
}
int main(){
	srand(19260817);
	int Q;
	scanf("%d",&Q);
	while(Q--){
		int mo,x;
		scanf("%d%d",&mo,&x);
		switch(mo){
			case 1:insert(x);break;
			case 2:erase(x);break;
			case 3:printf("%d\n",rnk(x));break;
			case 4:printf("%d\n",t[kth(root,x)].val);break;
			case 5:printf("%d\n",t[pre(x)].val);break;
			case 6:printf("%d\n",t[nxt(x)].val);break;
		}
	}
	return 0;
}

维护序列

#include<bits/stdc++.h>
#define L(p) t[p].son0
#define R(p) t[p].son1
using namespace std;
const int maxn=100003;
struct node{
	int son0,son1,sz;
	bool z;
}t[maxn];
int cnt,root;
void pushup(int p){t[p].sz=t[L(p)].sz+t[R(p)].sz+1;}
void solve(int p){if(p)swap(L(p),R(p)),t[p].z^=1;}
void pushdown(int p){
	if(t[p].z){
		solve(L(p)),solve(R(p));
		t[p].z=0;
	}
}
void output(int p){
	if(p==0)return;
	pushdown(p);
	output(L(p));
	printf("%d ",p);
	output(R(p));
}
void O(int p=root){
	output(p);
	puts("");
}
void split(int p,int k,int &x,int &y){
	if(p==0){x=y=0;return;}
	pushdown(p);
	if(t[L(p)].sz+1<=k){
		x=p;
		split(R(p),k-t[L(p)].sz-1,R(p),y);
	}
	else{
		y=p;
		split(L(p),k,x,L(p));
	}
	pushup(p);
}
void merge(int &p,int x,int y){
	if(x==0||y==0){p=x+y;return;}
	if(rand()%(t[x].sz+t[y].sz)<t[x].sz){
		pushdown(x);
		merge(R(x),R(x),y);
		pushup(x);
		p=x;
	}
	else{
		pushdown(y);
		merge(L(y),x,L(y));
		pushup(y);
		p=y;
	}
}
void build(int &p,int l,int r){
	if(l>r)return;
	p=(l+r)>>1;
	build(L(p),l,p-1);
	build(R(p),p+1,r);
	pushup(p);
}
void reverse(int l,int r){
	int x,y,z;
	split(root,l-1,x,y);
	split(y,r-l+1,y,z);
	solve(y);
	merge(y,x,y);
	merge(root,y,z);
}
int main(){
	srand(19260817);
	int n,Q;
	scanf("%d%d",&n,&Q);
	build(root,1,n);
	while(Q--){
		int x,y;
		scanf("%d%d",&x,&y);
		reverse(x,y);
	}
	O();
	return 0;
}

persistent

#include<bits/stdc++.h>
#define L(p) t[p].son[0]
#define R(p) t[p].son[1]
using namespace std;
namespace FASTIO{...}
const int maxn=200003;
struct node{
	int val,son[2],sz;
	long long sum;
	bool z;
}t[20000003];
int cnt,root[maxn];
int new_node(int k){
	cnt++;
	t[cnt].val=t[cnt].sum=k;
	t[cnt].sz=1;
	L(cnt)=R(cnt)=0;
	return cnt;
}
void pushup(int p){
	t[p].sz=t[L(p)].sz+t[R(p)].sz+1;
	t[p].sum=t[L(p)].sum+t[R(p)].sum+t[p].val;
}
void pushdown(int p){
	if(t[p].z){
		int l=0,r=0;
		if(L(p))t[r=++cnt]=t[L(p)],t[r].z^=1;
		if(R(p))t[l=++cnt]=t[R(p)],t[l].z^=1;
		L(p)=l,R(p)=r;
		t[p].z=0;
	}
}
void output(int p){
	if(p==0)return;
	pushdown(p);
	output(L(p));
	printf("val:%d sum:%lld son0:%d son1:%d\n",t[p].val,t[p].sum,t[L(p)].val,t[R(p)].val);
	output(R(p));
}
void O(int p){
	printf("### O ###\n");
	puts("############");
	output(p);
	puts("############");
}
void split(int p,int k,int &x,int &y){
	if(p==0){x=y=0;return;}
	pushdown(p);
	if(t[L(p)].sz+1<=k){
		x=++cnt;
		t[x]=t[p];
		split(R(p),k-t[L(p)].sz-1,R(x),y);
		pushup(x);
	}
	else{
		y=++cnt;
		t[y]=t[p];
		split(L(p),k,x,L(y));
		pushup(y);
	}
}
void merge(int &p,int x,int y){
	if(x==0||y==0){p=x+y;return;}
	if(rand()%(t[x].sz+t[y].sz)<t[x].sz){
		pushdown(x);
		merge(R(x),R(x),y);
		pushup(x);
		p=x;
	}
	else{
		pushdown(y);
		merge(L(y),x,L(y));
		pushup(y);
		p=y;
	}
}
void insert(int u,int v,int pos,int k){
	int x,y;
	split(root[v],pos,x,y);
	merge(x,x,new_node(k));
	merge(root[u],x,y);
}
void erase(int u,int v,int pos){
	int x,y,z;
	split(root[v],pos-1,x,y);
	split(y,1,y,z);
	merge(root[u],x,z);
}
void reverse(int u,int v,int l,int r){
	int x,y,z;
	split(root[v],l-1,x,y);
	split(y,r-l+1,y,z);
	t[y].z^=1;
	merge(y,x,y);
	merge(root[u],y,z);
}
long long query(int v,int l,int r){
	int x,y,z;
	split(root[v],l-1,x,y);
	split(y,r-l+1,y,z);
	long long ret=t[y].sum;
	merge(y,x,y);
	merge(root[v],y,z);
	return ret;
}
int main(){
	srand(19260817);
	int Q,v,mo;
	long long x,y,last=0;
	read(Q);
	for(int i=1;i<=Q;i++){
		read(v),read(mo),read(x);
		root[i]=root[v];
		x^=last;
		if(mo==1){
			read(y);
			y^=last;
			insert(i,v,x,y);
		}
		if(mo==2){
			erase(i,v,x);
		}
		if(mo==3){
			read(y);
			y^=last;
			reverse(i,v,x,y);
		}
		if(mo==4){
			read(y);
			y^=last;
			write(last=query(v,x,y)),pc('\n');
		}
	}
	flush();
	return 0;
}

String

KMP

#include<bits/stdc++.h>
using namespace std;
const int maxn=1000003;
int kmp[maxn];
char s1[maxn],s2[maxn];
int main(){
	scanf("%s%s",s1+1,s2+1);
	int l1=strlen(s1+1),l2=strlen(s2+1),pos=0;
	for(int i=2;i<=l2;i++){
		while(pos&&s2[pos+1]!=s2[i])pos=kmp[pos];
		if(s2[pos+1]==s2[i])pos++;
		kmp[i]=pos;
	}
	pos=0;
	for(int i=1;i<=l1;i++){
		while(pos&&s1[i]!=s2[pos+1])pos=kmp[pos];
		if(s1[i]==s2[pos+1])pos++;
		if(pos==l2){
			printf("%d\n",i-l2+1);
			pos=kmp[pos];
		}
	}
	for(int i=1;i<=l2;i++)printf("%d ",kmp[i]);
	return 0;
}

Hash

#include<bits/stdc++.h>
using namespace std;
const int maxn=10003;
char s[maxn];
int n,ha[maxn];
int hash(){
	static const int p1=15797,p2=1000000009;
	int ret=0;
	for(int i=0;s[i];i++){
		ret=(1ll*ret*p1+s[i])%p2;
	}
	return ret;
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%s",s);
		ha[i]=hash();
	}
	sort(ha+1,ha+n+1);
	printf("%d",int(unique(ha+1,ha+n+1)-ha-1));
	return 0;
}

Suffix array

#include<bits/stdc++.h>
#define maxn 1000003
#define mod 1000000007
#define O(a) printf(#a": ");for(int j=1;j<=n;j++)printf("%d ",a[j]);puts("")
#define DEBUG printf("%d:\n",(int)__LINE__);O(sa);O(rnk);O(tp);O(buc);O(height)
using namespace std;
char s[maxn];
int rnk[maxn],sa[maxn],tp[maxn],buc[maxn],n,m,height[maxn],a[maxn],f[maxn];
long long sum[maxn];
void bucsort(){
	for(int i=1;i<=m;i++)buc[i]=0;
	for(int i=1;i<=n;i++)buc[rnk[i]]++;
	for(int i=1;i<=m;i++)buc[i]+=buc[i-1];
	for(int i=n;i>=1;i--)sa[buc[rnk[tp[i]]]--]=tp[i];
}
void sufsort(){
	m=128;
	for(int i=1;i<=n;i++)rnk[i]=s[i],tp[i]=i;
	bucsort();
	for(int t=1,cnt=0;cnt<n;m=cnt,t<<=1){
//update tp
		cnt=0;
		for(int i=n-t+1;i<=n;i++)tp[++cnt]=i;
		for(int i=1;i<=n;i++){
			if(sa[i]>t)tp[++cnt]=sa[i]-t;
		}
//update sa
		bucsort();
//update rnk
		for(int i=1;i<=n;i++)tp[i]=rnk[i];
		rnk[sa[1]]=cnt=1;
		for(int i=2;i<=n;i++){
			rnk[sa[i]]=(tp[sa[i]]==tp[sa[i-1]]&&tp[sa[i]+t]==tp[sa[i-1]+t]?cnt:++cnt);
		}
	}
}
void geth(){
	int k=0;
	for(int i=1;i<=n;i++)rnk[sa[i]]=i;
	for(int i=1;i<=n;i++){
		if(rnk[i]==1)continue;
		if(k)k--;
		int j=sa[rnk[i]-1];
		while(i+k<=n&&j+k<=n&&s[i+k]==s[j+k])k++;
		height[rnk[i]]=k;
	}
}
bool cmp(int x,int y){return height[x]>height[y];}
int find(int x){return x!=f[x]?f[x]=find(f[x]):f[x];}
int main(){
	scanf("%s",s+1);
	n=strlen(s+1);
	sufsort(),geth();
	for(int i=1;i<=n;i++)a[i]=f[i]=i,sum[i]=1;
	sort(a+1,a+n+1,cmp);
	long long ans=0;
	for(int i=n,j=1;i>=1;i--){
		for(;j<=n&&height[a[j]]==i;j++){
			int x=find(sa[a[j]-1]),y=find(sa[a[j]]);
			sum[x]+=sum[y];
			ans=max(ans,(long long)i*sum[x]);
			f[y]=x;
		}
	}
	printf("%lld\n",ans);
	return 0;
}

Manacher

#include<bits/stdc++.h>
using namespace std;
const int maxn=22000005;
char t[maxn>>1],s[maxn];
int p[maxn];
int main(){
	scanf("%s",t+1);
	int N=strlen(t+1),n=0,mid=0,r=0,ans=1;
	s[++n]=-2,s[++n]=-1;
	for(int i=1;i<=N;i++)s[++n]=t[i],s[++n]=-1;
	for(int i=1;i<=n;i++){
		if(i<=r)p[i]=min(p[(mid<<1)-i],r-i+1);
		while(s[i+p[i]]==s[i-p[i]])p[i]++;
		if(i+p[i]-1>r)r=i+p[i]-1,mid=i;
		ans=max(ans,p[i]);
	}
	printf("%d\n",ans-1);
	return 0;
}

Geometry

const double eps=1e-10,INF=1e17;
typedef double tp;
int sgn(tp x){return x<-eps?-1:x>eps;}
// const double pi=acos(-1);
struct point{
	tp x,y;
	point(){}
	point(tp _x,tp _y):x(_x),y(_y){}
	void write()const{printf("%.4lf %.4lf\n",x,y);}
	bool operator<(point p)const{return sgn(x-p.x)==0?sgn(y-p.y)<0:sgn(x-p.x)<0;}
	bool operator==(point p)const{return sgn(x-p.x)==0&&sgn(y-p.y)==0;}
	point operator+(point p)const{return point(x+p.x,y+p.y);}
	point operator-(point p)const{return point(x-p.x,y-p.y);}
	point operator*(tp k)const{return point(x*k,y*k);}
	double norm()const{return x*x+y*y;}
	// double abs()const{return sqrt(x*x+y*y);}
};
tp dot(point u,point v){return u.x*v.x+u.y*v.y;}
tp cross(point u,point v){return u.x*v.y-v.x*u.y;}
double dist(point p1,point p2){return sqrt(double(dot(p1-p2,p1-p2)));}

point inter(point P,point v,point Q,point w){
	point u=P-Q;
	if(sgn(cross(v,w))==0){
		if(sgn(cross(Q-P,v))==0)return point(-INF,-INF); //chong he
		return point(INF,INF); //ping xing
	}
	tp t=cross(w,u)/cross(v,w);
	return P+v*t; //OK
}

bool seg_inter(point p1,point p2,point p3,point p4){
	return min(p1.x,p2.x)<=max(p3.x,p4.x)&&
	min(p3.x,p4.x)<=max(p1.x,p2.x)&&
	min(p1.y,p2.y)<=max(p3.y,p4.y)&&
	min(p3.y,p4.y)<=max(p1.y,p2.y)&&
	sgn(cross(p2-p1,p3-p1))*sgn(cross(p2-p1,p4-p1))<=0&&
	sgn(cross(p4-p3,p1-p3))*sgn(cross(p4-p3,p2-p3))<=0;
}
bool line_seg_inter(point l1,point l2,point p1,point p2){
	return sgn(cross(l2-l1,p1-l1))*sgn(cross(l2-l1,p2-l1))<=0;
}

int stk[maxn],cntcon;
point con[maxn];
void convex_hull(point a[],int n){
	cntcon=0;
	int top=2;
	stk[1]=1,stk[2]=2;
	for(int i=3;i<=n;i++){
		while(top>1&&cross(a[i]-a[stk[top]],a[stk[top]]-a[stk[top-1]])>0)top--;
		stk[++top]=i;
	}
	for(int i=1;i<top;i++){
		con[++cntcon]=a[stk[i]];
	}
	top=2;
	stk[1]=1,stk[2]=2;
	for(int i=3;i<=n;i++){
		while(top>1&&cross(a[i]-a[stk[top]],a[stk[top]]-a[stk[top-1]])<=0)top--;
		stk[++top]=i;
	}
	for(int i=top;i>1;i--){
		con[++cntcon]=a[stk[i]];
	}
}

double getS(const vector<point> &p){
	double ans=cross(p[0],p[p.size()-1]);
	for(int i=1;i<int(p.size());i++)ans+=cross(p[i],p[i-1]);
	return abs(ans)*0.5;
}

bool onright(point P,point S,point T){
	return sgn(cross(T-S,P-S))<0;
}

Math

Number theory

Combinatorics

Gauss

#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=103;
const double eps=1e-8;
int n;
double a[maxn][maxn];
int sgn(double x){return x<-eps?-1:x>eps;}
bool gauss(){
    for(int i=1;i<=n;i++){
        int p=i;
        for(int j=i+1;j<=n;j++)if(abs(a[j][i])>abs(a[p][i]))p=j;
        if(p!=i)for(int j=1;j<=n+1;j++)swap(a[i][j],a[p][j]);
        if(sgn(a[i][i])==0){
            puts("No Solution");
            return 0;
        }
        for(int j=i+1;j<=n+1;j++)a[i][j]/=a[i][i];
        a[i][i]=1;
        for(int j=1;j<=n;j++){
            if(i!=j){
                for(int k=i+1;k<=n+1;k++)a[j][k]-=a[j][i]*a[i][k];
                a[j][i]=0;
            }
        }
    }
    return 1;
}
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]);
        }
    }
    if(!gauss())return 0;
    for(int i=1;i<=n;i++)printf("%.2lf\n",a[i][n+1]);
    return 0;
}

Linear basis

#include<bits/stdc++.h>
using namespace std;
const int maxlog=51;
int n;
long long p[maxlog];
void insert(long long x){
	for(int i=maxlog-1;i>=0;i--){
		if((x>>i)&1){
			if(p[i]==0){
				p[i]=x;
				break;
			}
			else x^=p[i];
		}
	}
}
long long query(){
	long long ret=0;
	for(int i=maxlog-1;i>=0;i--){
		if((ret^p[i])>ret)ret^=p[i];
	}
	return ret;
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		long long x;
		scanf("%lld",&x);
		insert(x);
	}
	printf("%lld",query());
	return 0;
}

BSGS

unordered_map<int,int> mp;
int bsgs(int y,int z){
	if(z==1)return 0;
	if(y%mod==0)return -1;
	mp.clear();
	int m=sqrt(mod)+1,ji=z;
	for(int b=0;b<=m;b++){
		mp[ji]=b;
		ji=mul(ji,y);
	}
	int tmp=qpow(y,m);
	ji=1;
	for(int a=1;a<=m;a++){
		ji=mul(ji,tmp);
		if(mp.count(ji))return a*m-mp[ji];
	}
	return -1;
}
posted @ 2019-10-12 21:15  chc_1234567890  阅读(432)  评论(0编辑  收藏