模板集

#include<cmath>
#include<queue>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
//多项式全家桶 
namespace polynomial{
	const int maxn=1<<20,mod=998244353;
	int mo(const int x){
		return x>=mod?x-mod:x;
	}
	int power(int a,int x){
		int re=1;
		while(x){
			if(x&1)re=1ll*re*a%mod;
			a=1ll*a*a%mod,x>>=1;
		}
		return re;
	}
	const int g_=3;
	int rev[maxn],gN[maxn];
	void initNTT(int m,int&n){
		n=1;int cn=-1;
		while(n<m)n<<=1,++cn;
		gN[0]=1;gN[1]=power(g_,(mod-1)/n);
		for(int i=1;i<n;++i)
			rev[i]=(rev[i>>1]>>1)|((i&1)<<cn),
			gN[i]=1ll*gN[i-1]*gN[1]%mod;
	}
	void NTT(int*F,int n,int rv){
		for(int i=0;i<n;++i)if(rev[i]<i)
			F[i]^=F[rev[i]]^=F[i]^=F[rev[i]];
		for(int mid=1;mid<n;mid<<=1){
			const int len=mid<<1,gn=n/len;
			for(int i=0;i<n;i+=len){
				for(int j=0,g=0;j<mid;++j,g+=gn){
					int l=i+j,r=l+mid;
					int L=F[l],R=1ll*F[r]*gN[g]%mod;
					F[l]=mo(L+R),F[r]=mo(mod-R+L);
				}
			}
		}
		if(!rv)return;std::reverse(F+1,F+n);int I=mod-(mod-1)/n;
		for(int i=0;i<n;++i)F[i]=1ll*F[i]*I%mod;
	}
	int Inv[maxn];
	void inv(int*F,int*G,int n){
		//G(x)=inv(F(x)) mod x^n;
		if(n==1)return G[0]=power(F[0],mod-2),void();
		inv(F,G,(n+1)>>1);for(int i=(n+1)>>1;i<n;++i)G[i]=0;
		int cp=n;initNTT((n+1)*2,n);
		for(int i=0;i<cp;++i)Inv[i]=F[i];for(int i=cp;i<n;++i)Inv[i]=G[i]=0;
		NTT(Inv,n,0);NTT(G,n,0);for(int i=0;i<n;++i)
			G[i]=1ll*G[i]*mo(mod-1ll*G[i]*Inv[i]%mod+2)%mod;
		NTT(G,n,1);for(int i=cp;i<n;++i)G[i]=0;
	}
	int Ln[maxn];
	void ln(int*F,int*G,int n){
		//G(x)=ln(F(x)) mod x^n;
		for(int i=0;i<n;++i)Ln[i]=0;
		inv(F,Ln,n);int cp=n;
		initNTT((n+1)*2,n);
		for(int i=0;i<cp;++i)G[i]=1ll*F[i+1]*(i+1)%mod;
		for(int i=cp;i<n;++i)G[i]=Ln[i]=0;NTT(G,n,0);NTT(Ln,n,0);
		for(int i=0;i<n;++i)G[i]=1ll*G[i]*Ln[i]%mod;NTT(G,n,1);
		for(int i=cp-1;i>=1;--i)G[i]=1ll*G[i-1]*power(i,mod-2)%mod;
		G[0]=0;for(int i=cp;i<n;++i)G[i]=0;
	}
	int Exp[maxn];
	void exp(int*F,int*G,int n){
		//G(x)=exp(F(x)) mod x^n;
		if(n==1)return G[0]=1,void();exp(F,G,(n+1)>>1);
		for(int i=(n+1)>>1;i<n;++i)G[i]=0;
		for(int i=0;i<n;++i)Exp[i]=0;ln(G,Exp,n);
		for(int i=0;i<n;++i)Exp[i]=mo(mod-Exp[i]+F[i]+(i==0));
		int cp=n;initNTT((n+1)*2,n);
		for(int i=cp;i<n;++i)Exp[i]=G[i]=0;NTT(G,n,0);NTT(Exp,n,0);
		for(int i=0;i<n;++i)G[i]=1ll*G[i]*Exp[i]%mod;
		NTT(G,n,1);for(int i=cp;i<n;++i)G[i]=0;
	}
	int Power[maxn];
	void power(int*F,int*G,int n,int m0,int m1,int m2){
		//G(x)=power(F(x),m) mod x^n;
		//m0=m%mod m1=m%(mod-1) m2=stand for m
		int no=0;while(no<n&&F[no]==0)++no;
		if(1ll*no*m2>=n){for(int i=0;i<n;++i)G[i]=0;return;}
		int V=F[no],I=power(V,mod-2);
		for(int i=0;i+no<n;++i)G[i]=1ll*F[i+no]*I%mod,Power[i]=0;
		for(int i=n-no;i<n;++i)G[i]=Power[i]=0;ln(G,Power,n);
		for(int i=0;i<n;++i)Power[i]=1ll*Power[i]*m0%mod;
		exp(Power,G,n);V=power(V,m1);no*=m2;
		for(int i=n-1;i>=no;--i)G[i]=1ll*G[i-no]*V%mod;
		for(int i=no-1;i>=0;--i)G[i]=0;
	}
	int Divide0[maxn],Divide1[maxn];
	void divide(int*F,int*G,int*Q,int*R,int n,int m){
		//F(x)=Q(x)G(x)+R(x) Q(x)? R(x)? deg(F)=n-1 deg(G)=m-1
		int tn=n-m+1;
		for(int i=0;i<tn;++i)Divide1[i]=(m>=i+1?G[m-i-1]:0);
		inv(Divide1,Divide0,tn);
		for(int i=0;i<tn;++i)Divide1[i]=(n>=i+1?F[n-i-1]:0);
		int cp=tn;initNTT((n+1)*2,tn);
		NTT(Divide0,tn,0);NTT(Divide1,tn,0);
		for(int i=0;i<tn;++i)Q[i]=1ll*Divide0[i]*Divide1[i]%mod;
		NTT(Q,tn,1);for(int i=cp;i<tn;++i)Q[i]=0;std::reverse(Q,Q+cp);
		for(int i=0;i<tn;++i)Divide0[i]=Q[i],Divide1[i]=G[i];
		NTT(Divide0,tn,0);NTT(Divide1,tn,0);
		for(int i=0;i<tn;++i)R[i]=1ll*Divide0[i]*Divide1[i]%mod;
		NTT(R,tn,1);for(int i=0;i<tn;++i)R[i]=mo(mod-R[i]+F[i]);
	}
}
//平衡树 
namespace Treap{
	const int maxn=100005;
	struct Node{
		int l,r,sz,val;
		Node(int l=0,int r=0,int sz=0,int val=0):
			l(l),r(r),sz(sz),val(val){}
	}P[maxn];
	int tot;
	void pushup(int x){
		P[x].sz=P[P[x].l].sz+P[P[x].r].sz+1;
	}
	void pushdown(int x){
		//
	}
	int build(int val){
		P[++tot]=Node(0,0,1,val);return tot;
	}
	//left_size=k
	void split_size(int x,int&l,int&r,int k){
		if(!x)return l=r=0,void();
		pushdown(x);int o=P[P[x].l].sz+1;
		if(k>=o)l=x,split_size(P[x].r,P[l].r,r,k-o);
		else r=x,split_size(P[x].l,l,P[r].l,k);
		pushup(x);
	}
	//left_val<=v
	void split_value(int x,int&l,int&r,int v){
		if(!x)return l=r=0,void();
		pushdown(x);int o=P[x].val;
		if(v>=o)l=x,split_value(P[x].r,P[l].r,r,v);
		else r=x,split_value(P[x].l,l,P[r].l,v);
		pushup(x);
	}
	int rd(int l,int r){
		return 1ll*rand()*(l+r)<1ll*RAND_MAX*l;
	}
	void merge_tree(int&x,int l,int r){
		if(!l||!r)return x=l|r,void();
		pushdown(x);
		if(rd(P[l].sz,P[r].sz))x=l,merge_tree(P[x].r,P[l].r,r);
		else x=r,merge_tree(P[x].l,l,P[r].l);
		pushup(x);
	}
	int root;
	void ins(int val){
		int x,y;
		split_value(root,x,y,val);
		merge_tree(x,x,build(val));
		merge_tree(root,x,y);
	}
	void del(int val){
		int x,y,z;
		split_value(root,x,y,val-1);
		split_value(y,y,z,val);
		merge_tree(y,P[y].l,P[y].r);
		merge_tree(y,y,z);
		merge_tree(root,x,y);
	}
	int rank(int val){
		int x,y;
		split_value(root,x,y,val-1);
		int ans=P[x].sz+1;
		merge_tree(root,x,y);
		return ans;
	}
	int knar(int sz,int&rt=root){
		int x,y,z;
		split_size(rt,x,y,sz-1);
		split_size(y,y,z,1);
		int ans=P[y].val;
		merge_tree(y,y,z);
		merge_tree(rt,x,y);
		return ans;
	}
	//max_val<val
	int lower(int val){
		int x,y,z;
		split_value(root,y,z,val-1);
		split_size(y,x,y,P[y].sz-1);
		int ans=P[y].val;
		merge_tree(y,x,y);
		merge_tree(root,y,z);
		return ans;
	}
	//min_val>val
	int upper(int val){
		int x,y,z;
		split_value(root,x,y,val);
		split_size(y,y,z,1);
		int ans=P[y].val;
		merge_tree(y,y,z);
		merge_tree(root,x,y);
		return ans;
	}
	void print(int x){
		if(!x)return;
		putchar('(');print(P[x].l);
		printf("%d ",P[x].val);
		print(P[x].r);putchar(')');
	}
}
namespace Splay{
	const int maxn=100005;
	#define root P[0].s[0]
	struct Node{
		int s[2],p,sz,val;
		Node(int l=0,int r=0,int p=0,int sz=0,int val=0){
			this->s[0]=l,this->s[1]=r;
			this->p=p,this->sz=sz,this->val=val;
		}
	}P[maxn];
	int tot;
	void pushup(int x){
		P[x].sz=P[P[x].s[0]].sz+P[P[x].s[1]].sz+1;
	}
	void pushdown(int x){
		//
	}
	int identify(int x){
		return P[P[x].p].s[1]==x;
	}
	void connect(int p,int x,int t){
		P[p].s[t]=x;if(x)P[x].p=p;
	}
	void rotate(int x){
		int o=identify(x),p=P[x].p;
		connect(p,P[x].s[!o],o);
		connect(P[p].p,x,identify(p));
		connect(x,p,!o);
		pushup(p);pushup(x);
	}
	//keep splay, so the information can always be updated.
	void splay(int st,int ed){
		ed=P[ed].p;
		while(P[st].p!=ed){
			int up=P[st].p;
			if(P[up].p!=ed){
				if(identify(up)==identify(st))
					rotate(up);
				else
					rotate(st);
			}
			rotate(st);
		}
	}
	int build(int val,int pa){
		P[++tot]=Node(0,0,pa,1,val);
		return tot;
	}
	//splay val to the root
	void find(int val){
		int x=root;
		while(x){
			pushdown(x);
			if(P[x].val==val)
				return splay(x,root);
			int t=P[x].val<val;
			x=P[x].s[t];
		}
	}
	void ins(int val){
		if(!root)
			root=build(val,0);
		else{
			int x=root;
			while(x){
				pushdown(x);
				int t=P[x].val<val;
				if(!P[x].s[t]){
					splay(P[x].s[t]=build(val,x),root);
					return;
				}
				x=P[x].s[t];
			}
		}
	}
	void del(int val){
		find(val);
		if(!P[root].s[0])
			connect(0,P[root].s[1],0);
		else{
			int x=P[root].s[0];
			while(P[x].s[1]){
				pushdown(x);
				x=P[x].s[1];
			}
			pushdown(x);
			splay(x,P[root].s[0]);
			connect(P[root].s[0],P[root].s[1],1);
			pushup(P[root].s[0]);
			connect(0,P[root].s[0],0);
		}
	}
	int rank(int val){
		int ans=1;
		int x=root;
		while(x){
			pushdown(x);
			int t=P[x].val<val;
			if(t)ans+=P[P[x].s[0]].sz+1;
			if(!P[x].s[t]){
				splay(x,root);
				x=0;
			}
			else
				x=P[x].s[t];
		}
		return ans;
	}
	int knar(int sz){
		int x=root;
		while(x){
			pushdown(x);
			int o=P[P[x].s[0]].sz+1;
			if(o==sz){
				splay(x,root);
				return P[x].val;
			}
			if(sz>o)
				sz-=o,x=P[x].s[1];
			else
				x=P[x].s[0];
		}
		return 0;
	}
	#define inf 0x3f3f3f3f
	int lower(int val){
		int x=root,ans=-inf;
		while(x){
			pushdown(x);
			int t=P[x].val<val;
			if(t)ans=P[x].val;
			if(!P[x].s[t]){
				splay(x,root);x=0;
			}
			else x=P[x].s[t];
		}
		return ans;
	}
	int upper(int val){
		int x=root,ans=inf;
		while(x){
			pushdown(x);
			int t=P[x].val<=val;
			if(!t)ans=P[x].val;
			if(!P[x].s[t]){
				splay(x,root);x=0;
			}
			else x=P[x].s[t];
		}
		return ans;
	}
	#undef inf
}
//动态树 
namespace LinkCutTree{
	const int maxn=100005;
	struct Node{
		int s[2],p,val,rv,sm;
		//rv 用来维护换根操作 
		//这里 sm 举例求路径异或和 
		Node(int l=0,int r=0,int p=0,int val=0,int rv=0,int sm=0){
			this->s[0]=l,this->s[1]=r;this->p=p;
			this->val=val,this->rv=rv,this->sm=sm;
		}
	}P[maxn];
	void push(int x){
		if(x){
			std::swap(P[x].s[0],P[x].s[1]);
			P[x].rv^=true;
		}
	}
	void pushdown(int x){
		if(!P[x].rv)return;P[x].rv=false;
		push(P[x].s[0]);push(P[x].s[1]);
	}
	void pushup(int x){
		P[x].sm=P[P[x].s[0]].sm^P[P[x].s[1]].sm^P[x].val;
	}
	bool isroot(int x){
		return P[P[x].p].s[0]!=x&&P[P[x].p].s[1]!=x;
	}
	int identify(int x){
		return P[P[x].p].s[1]==x;
	}
	void connect(int p,int x,int t){
		P[p].s[t]=x;if(x)P[x].p=p;
	}
	void rotate(int x){
		int o=identify(x),p=P[x].p;
		connect(p,P[x].s[!o],o);
		if(isroot(p))P[x].p=P[p].p;
		else connect(P[p].p,x,identify(p));
		connect(x,p,!o);
		pushup(p);pushup(x);
	}
	//just splay x to the root
	int st[maxn];
	void splay(int x){
		//remember to pushdown!
		int tp=0;
		while(!isroot(x))
			st[++tp]=x,x=P[x].p;
		st[++tp]=x;
		while(tp)pushdown(st[tp--]);
		x=st[1];
		while(!isroot(x)){
			int p=P[x].p;
			if(!isroot(p)){
				if(identify(p)==identify(x))
					rotate(p);
				else
					rotate(x);
			}
			rotate(x);
		}
	}
	void access(int x){
		//make x access to the real root
		for(int y=0;x;y=x,x=P[x].p){
			splay(x);P[x].s[1]=y;pushup(x);
		}
	}
	void makeroot(int x){
		access(x);splay(x);push(x);
	}
	//split the path x-?-y
	void split(int x,int y){
		makeroot(x);access(y);splay(y);
	}
	int ask(int x,int y){
		split(x,y);return P[y].sm;
	}
	void modify(int x,int val){
		access(x);splay(x);
		P[x].val=val;pushup(x);
	}
	void link(int x,int y){
		split(x,y);
		//only if x and y are unconnected
		if(!P[x].p)P[x].p=y;
	}
	void cut(int x,int y){
		split(x,y);
		//only if the edge (x,y) exists
		if(P[y].s[0]==x){
			P[x].p=P[y].s[0]=0;
			pushup(y);
		}
	}
}
//图论算法 
//最短路
namespace ShortestPath{
	const int maxn=100005,maxm=200005;
	struct Edge{
		int v,w,nt;
		Edge(int v=0,int w=0,int nt=0):
			v(v),w(w),nt(nt){}
	}e[maxm];
	int num,hd[maxn];
	void qwq(int u,int v,int w){
		e[++num]=Edge(v,w,hd[u]);hd[u]=num;
	}
	struct Val{
		int v;long long w;
		Val(int v=0,long long w=0):
			v(v),w(w){}
		bool operator < (const Val o)const{
			return w>o.w;
		}
	};
	long long dis[maxn];
	std::priority_queue<Val>q;
	void dijkstra_heap(int s){
		memset(dis,0x3f,sizeof dis);
		q.push(Val(s,dis[s]=0));
		while(!q.empty()){
			Val tmp=q.top();q.pop();
			if(tmp.w!=dis[tmp.v])continue;
			int u=tmp.v;
			for(int i=hd[u];i;i=e[i].nt){
				int v=e[i].v,w=e[i].w;
				if(dis[v]>dis[u]+w){
					q.push(Val(v,dis[v]=dis[u]+w));
				}
			}
		}
	}
	#define inf 0x3f3f3f3f3f3f3f3fll
	int lock[maxn];
	void dijkstra(int s,int n){
		memset(dis,0x3f,sizeof dis);
		memset(lock,0,sizeof lock);
		dis[s]=0;
		for(int i=1;i<=n;++i){
			long long mv=inf;int u=0;
			for(int j=1;j<=n;++j){
				if(!lock[j]&&dis[j]<mv){
					mv=dis[u=j];
				}
			}
			lock[u]=true;
			for(int j=hd[u];j;j=e[j].nt){
				int v=e[j].v,w=e[j].w;
				if(dis[v]>dis[u]+w)
					dis[v]=dis[u]+w;
			}
		}
	}
	#undef inf
}
//K短路 
namespace KShortestPath{
	const int maxn=100005,maxm=200005;
	struct Edge{
		int v,w,nt;
		Edge(int v=0,int w=0,int nt=0):
			v(v),w(w),nt(nt){}
	}e[maxm];
	int num,hd[maxn];
	void qwq(int u,int v,int w){
		e[++num]=Edge(v,w,hd[u]);hd[u]=num;
	}
	struct Val{
		int v;long long w;
		Val(int v=0,long long w=0):
			v(v),w(w){}
		bool operator < (const Val o)const{
			return w>o.w;
		}
	};
	long long dis[maxn];
	int st[maxn],tp=0;
	std::priority_queue<Val>q;
	void dijkstra(int s){
		memset(dis,0x3f,sizeof dis);
		q.push(Val(s,dis[s]=0));
		while(!q.empty()){
			Val tmp=q.top();q.pop();
			if(tmp.w!=dis[tmp.v])continue;
			int u=st[++tp]=tmp.v;
			for(int i=hd[u];i;i=e[i].nt){
				int v=e[i].v,w=e[i].w;
				if(dis[v]>dis[u]+w){
					q.push(Val(v,dis[v]=dis[u]+w));
				}
			}
		}
	}
	struct Node{
		int l,r,dis;Val v;
		Node(int l=0,int r=0,int dis=0,Val v=Val()):
			l(l),r(r),dis(dis),v(v){}
	}P[maxm+maxn*18];
	int tot;
	void update(int x){
		if(P[P[x].l].dis<P[P[x].r].dis){
			std::swap(P[x].l,P[x].r);
			P[x].dis=P[P[x].r].dis+1;
		}
	}
	void ins(int&x,Val v){
		if(!x){
			P[++tot]=Node(0,0,1,v);x=tot;
			return;
		}
		if(P[x].v<v){
			P[++tot]=Node(x,0,1,v);x=tot;
			return;
		}
		ins(P[x].l,v);
		update(x);
	}
	void merge(int&x,int l,int r){
		if(!l||!r)return x=l|r,void();
		if(P[l].v<P[r].v)std::swap(l,r);
		x=++tot;P[x]=P[l];
		merge(P[x].r,P[l].r,r);
		update(x);
	}
	#define inf 0x3f3f3f3f3f3f3f3fll
	int rt[maxn],pre[maxn];
	long long solve(int s,int t,int k,int n){
		dijkstra(s);
		if(k==1)return dis[t];
		for(int u=1;u<=n;++u){
			for(int i=hd[u];i;i=e[i].nt){
				int v=e[i].v,w=e[i].w;
				if(dis[u]>=inf)continue;
				if(!pre[v]&&dis[v]==dis[u]+w)pre[v]=u;
				else ins(rt[v],Val(u,dis[u]+w-dis[v]));
			}
		}
		for(int i=2;i<=tp;++i){
			int u=st[i];
			merge(rt[u],rt[u],rt[pre[u]]);
		}
		if(rt[t]){
			q.push(Val(rt[t],P[rt[t]].v.w));
		}
		long long ans=0;
		while((k--)&&!q.empty()){
			Val tmp=q.top();q.pop();int node=tmp.v;ans=tmp.w;
			if(P[node].l)q.push(Val(P[node].l,ans-P[node].v.w+P[P[node].l].v.w));
			if(P[node].r)q.push(Val(P[node].r,ans-P[node].v.w+P[P[node].r].v.w));
			if(rt[P[node].v.v])q.push(Val(rt[P[node].v.v],ans+P[rt[P[node].v.v]].v.w));
		}
		if(k==-1)return ans+dis[t];
		else return inf;
	}
	#undef inf
}
//有向图强连通分量 
//Strongly Connected Component
namespace SCC{
	const int maxn=100005,maxm=200005;
	struct Edge{
		int v,nt;
		Edge(int v=0,int nt=0):
			v(v),nt(nt){}
	}e[maxm],e2[maxm];
	//Kosaraju 要存反图 
	int num,hd[maxn];
	void qwq(int u,int v){
		e[++num]=Edge(v,hd[u]),hd[u]=num;
		e2[num]=Edge(u,hd[v]),hd[v]=num;
	}
	int dfn[maxn],low[maxn],cnt;
	int st[maxn],in[maxn],tp;
	int scn,sc[maxn];
	void tarjan(int u){
		dfn[u]=low[u]=++cnt;
		in[st[++tp]=u]=true;
		for(int i=hd[u];i;i=e[i].nt){
			int v=e[i].v;
			if(!dfn[v]){
				tarjan(v);
				low[u]=std::min(low[u],low[v]);
			}
			else if(in[v])
				low[u]=std::min(low[u],dfn[v]);
		}
		if(dfn[u]==low[u]){
			//These vertice form a scc
			++scn;
			while(st[tp]!=u){
				in[st[tp]]=false;
				sc[st[tp]]=scn;
				--tp;
			}
			in[st[tp--]]=false;
			sc[u]=scn;
		}
	}
	void solve_tarjan(int n){
		for(int i=1;i<=n;++i)
			if(!dfn[i])tarjan(i);
	}
	void kosaraju1(int u){
		dfn[u]=true;
		for(int i=hd[u];i;i=e[i].nt){
			int v=e[i].v;
			if(dfn[v])continue;
			kosaraju1(v);
		}
		st[dfn[u]=++tp]=u;
	}
	void kosaraju2(int u){
		sc[u]=scn;
		for(int i=hd[u];i;i=e[i].nt){
			int v=e[i].v;
			if(sc[v])continue;
			kosaraju2(v);
		}
	}
	void solve_kosaraju(int n){
		for(int i=1;i<=n;++i)
			if(!dfn[i])kosaraju1(i);
		for(int i=n;i>=1;--i)
			if(!sc[st[i]])++scn,kosaraju2(st[i]);
	}
}
//无向图点双连通分量 
//Point Biconnected Component
namespace PBC{
	const int maxn=100005,maxm=200005;
	struct Edge{
		int v,nt;
		Edge(int v=0,int nt=0):
			v(v),nt(nt){}
	}e[maxm*2];
	int hd[maxn],num;
	void qwq(int u,int v){
		e[++num]=Edge(v,hd[u]),hd[u]=num;
	}
	int dfn[maxn],low[maxn],cnt;
	int st[maxn],tp;
	//注意栈中最后还会剩一个元素 
	void tarjan(int u){
		dfn[u]=low[u]=++cnt;st[++tp]=u;
		for(int i=hd[u];i;i=e[i].nt){
			int v=e[i].v;
			if(!dfn[v]){
				tarjan(v);
				low[u]=std::min(low[u],low[v]);
				if(low[v]==dfn[u]){
					//These vertice with u form a pbc or an edge
					while(st[tp]!=v){
						--tp;
					}
					--tp;
				}
			}
			else low[u]=std::min(low[u],dfn[v]);
		}
	}
	void solve(int n){
		for(int i=1;i<=n;++i){
			if(!dfn[i])tarjan(i),--tp;
		}
	}
}
//无向图边双连通分量 
//Edge Biconnected Component
namespace EBC{
	const int maxn=500005,maxm=2000005;
	struct Edge{
		int v,nt;
		Edge(int v=0,int nt=0):
			v(v),nt(nt){}
	}e[maxm*2];
	int hd[maxn],num=1;
	void qwq(int u,int v){
		e[++num]=Edge(v,hd[u]),hd[u]=num;
	}
	int dfn[maxn],low[maxn],cnt;
	int st[maxn],tp;
	void tarjan(int u,int te){
		dfn[u]=low[u]=++cnt;st[++tp]=u;
		for(int i=hd[u];i;i=e[i].nt){
			if(i==te)continue;
			//remember to delete the tree-edge
			int v=e[i].v;
			if(!dfn[v]){
				tarjan(v,i^1);
				low[u]=std::min(low[u],low[v]);
			}
			else low[u]=std::min(low[u],dfn[v]);
		}
		if(dfn[u]==low[u]){
			//These vertice form an ebc or just a point
			while(st[tp]!=u){
				--tp;
			}
			--tp;
		}
	}
	void solve(int n){
		for(int i=1;i<=n;++i)
			if(!dfn[i])tarjan(i,0);
	}
}
//网络流 
namespace Dinic{
	const int maxn=205,maxm=5005;
	struct Edge{
		int v,w,nt;
		Edge(int v=0,int w=0,int nt=0):
			v(v),w(w),nt(nt){}
	}e[maxm*2];
	int hd[maxn],num=1;
	void qwq(int u,int v,int w){
		e[++num]=Edge(v,w,hd[u]);hd[u]=num;
		e[++num]=Edge(u,0,hd[v]);hd[v]=num;
	}
	int n,S,T,q[maxn],dis[maxn];
	int bfs(void){
		//n编号最大 
		for(int i=1;i<=n;++i)dis[i]=0;
		int fro=0,bac=0;
		dis[q[bac++]=S]=1;
		while(fro<bac){
			int u=q[fro++];
			for(int i=hd[u];i;i=e[i].nt){
				int v=e[i].v,w=e[i].w;
				if(w&&!dis[v])dis[q[bac++]=v]=dis[u]+1;
			}
		}
		return dis[T];
	}
	int cur[maxn];
	long long dfs(int u,long long lef){
		if(u==T)return lef;long long re=0;
		for(int&i=cur[u];i;i=e[i].nt){
			int v=e[i].v,w=e[i].w;
			if(w&&dis[v]==dis[u]+1){
				int tmp=dfs(v,w<lef?w:lef);
				e[i].w-=tmp,e[i^1].w+=tmp;
				lef-=tmp,re+=tmp;
				if(!lef)break;
			}
		}
		return re;
	}
	#define inf 0x3f3f3f3f
	long long dinic(void){
		long long max_flow=0;
		while(bfs()){
			for(int i=1;i<=n;++i)cur[i]=hd[i];
			max_flow+=dfs(S,inf);
		}
		return max_flow;
	}
	#undef inf
}
//费用流 
namespace MCMF_SPFA{
	const int maxn=5005,maxm=50005;
	struct Edge{
		int v,w,f,nt;
		Edge(int v=0,int w=0,int f=0,int nt=0):
			v(v),w(w),f(f),nt(nt){}
	}e[maxm*2];
	int hd[maxn],num=1;
	void qwq(int u,int v,int w,int f){
		e[++num]=Edge(v,w,f,hd[u]),hd[u]=num;
		e[++num]=Edge(u,0,-f,hd[v]),hd[v]=num;
	}
	int n,S,T;
	int in[maxn],q[maxn];
	int dis[maxn],flow[maxn],pre[maxn];
	#define inf 0x3f3f3f3f
	int spfa(void){
		for(int i=1;i<=n;++i)
			flow[i]=0,dis[i]=inf,pre[i]=0;
		int fro=0,bac=0;
		q[bac++]=S;
		dis[S]=0;
		flow[S]=inf;
		while(fro!=bac){
			int u=q[fro++];if(fro==maxn)fro=0;
			for(int i=hd[u];i;i=e[i].nt){
				int v=e[i].v,w=e[i].w,f=e[i].f;
				if(w&&dis[v]>dis[u]+f){
					pre[v]=i;dis[v]=dis[u]+f;
					flow[v]=std::min(flow[u],w);
					if(!in[v]){
						in[q[bac++]=v]=true;
						if(bac==maxn)bac=0;
					}
				}
			}
			in[u]=false;
		}
		return flow[T];
	}
	void solve(void){
		int max_flow=0,min_cost=0;
		while(spfa()){
			max_flow+=flow[T];
			min_cost+=flow[T]*dis[T];
			int x=T;
			while(x){
				e[pre[x]].w-=flow[T];
				e[pre[x]^1].w+=flow[T];
				x=e[pre[x]^1].v;
			}
		}
	}
}
//PS:这个 dijkstra 不一定是正优化 
namespace MCMF_dijkstra{
	const int maxn=5005,maxm=50005;
	struct Edge{
		int v,w,f,nt;
		Edge(int v=0,int w=0,int f=0,int nt=0):
			v(v),w(w),f(f),nt(nt){}
	}e[maxm*2];
	int hd[maxn],num=1;
	void qwq(int u,int v,int w,int f){
		e[++num]=Edge(v,w,f,hd[u]),hd[u]=num;
		e[++num]=Edge(u,0,-f,hd[v]),hd[v]=num;
	}
	int n,S,T;
	int in[maxn],q[maxn];
	int h[maxn],dis[maxn],flow[maxn],pre[maxn];
	#define inf 0x3f3f3f3f
	void spfa(void){
		for(int i=1;i<=n;++i)h[i]=inf;
		int fro=0,bac=0;
		q[bac++]=S;h[S]=0;
		while(fro!=bac){
			int u=q[fro++];if(fro==maxn)fro=0;
			for(int i=hd[u];i;i=e[i].nt){
				int v=e[i].v,w=e[i].w,f=e[i].f;
				if(w&&h[v]>h[u]+f){
					h[v]=h[u]+f;
					if(!in[v]){
						in[q[bac++]=v]=true;
						if(bac==maxn)bac=0;
					}
				}
			}
			in[u]=false;
		}
	}
	struct Val{
		int v,w;
		Val(int v=0,int w=0):
			v(v),w(w){}
		bool operator < (const Val o)const{
			return w>o.w;
		}
	};
	std::priority_queue<Val>hp;
	#define inf 0x3f3f3f3f
	int dijkstra(void){
		for(int i=1;i<=n;++i)
			dis[i]=inf,flow[i]=pre[i]=0;
		hp.push(Val(S,dis[S]=0));flow[S]=inf;
		while(!hp.empty()){
			Val tmp=hp.top();hp.pop();
			int u=tmp.v;if(tmp.w!=dis[u])continue;
			for(int i=hd[u];i;i=e[i].nt){
				int v=e[i].v,w=e[i].w,f=e[i].f;
				if(w&&dis[v]>dis[u]-h[v]+h[u]+f){
					hp.push(Val(v,dis[v]=dis[u]-h[v]+h[u]+f));
					flow[v]=std::min(flow[u],w);pre[v]=i;
				}
			}
		}
		return flow[T];
	}
	#undef inf
	void solve(void){
		int max_flow=0,min_cost=0;
		spfa();
		while(dijkstra()){
			max_flow+=flow[T];
			min_cost+=flow[T]*(dis[T]+h[T]);
			int x=T;
			while(x){
				e[pre[x]].w-=flow[T];
				e[pre[x]^1].w+=flow[T];
				x=e[pre[x]^1].v;
			}
			for(int i=1;i<=n;++i)h[i]=dis[i];
		}
		printf("%d %d\n",max_flow,min_cost);
	}
}
//最小树形图 
//Directed Minimum Spanning Tree
namespace DMST{
	const int maxn=100005,maxm=200005;
	struct Val{
		int v,w;
		Val(int v=0,int w=0):
			v(v),w(w){}
		Val operator += (const int o){
			this->w=this->w+o;return *this;
		}
		bool operator < (const Val o)const{
			return w<o.w;
		}
	};
	struct Node{
		int l,r,dis,laz;Val v;
		Node(int l=0,int r=0,int dis=0,int laz=0,Val v=Val()):
			l(l),r(r),dis(dis),laz(laz),v(v){}
	}P[maxm];
	int tot;
	void push(int x,int laz){
		P[x].laz+=laz;
		P[x].v+=laz;
	}
	void pushdown(int x){
		if(!P[x].laz)return;
		push(P[x].l,P[x].laz);
		push(P[x].r,P[x].laz);
		P[x].laz=0;
	}
	void pushup(int x){
		if(P[P[x].l].dis<P[P[x].r].dis)
			std::swap(P[x].l,P[x].r);
		P[x].dis=P[P[x].r].dis+1;
	}
	int newnode(Val v){
		P[++tot]=Node(0,0,1,0,v);
		return tot;
	}
	void merge(int&x,int l,int r){
		if(!l||!r)return x=l|r,void();
		pushdown(l);pushdown(r);
		if(P[r].v<P[l].v)l^=r^=l^=r;
		x=l;merge(P[x].r,P[l].r,r);
		return pushup(x);
	}
	void pop(int&x){
		pushdown(x);
		merge(x,P[x].l,P[x].r);
	}
	int rt[maxn];
	int id[maxn];
	int vis[maxn],cnt;
	int st[maxn],tp;
	int find(int x){
		return id[x]==x?x:id[x]=find(id[x]);
	}
	#define inf 0x3f3f3f3f
	int dfs(int u){
		if(vis[u]&&vis[u]<cnt)return 0;
		if(vis[u]==cnt){
			while(st[tp]!=u){
				id[st[tp]]=u;
				merge(rt[u],rt[u],rt[st[tp]]);
				--tp;
			}
		}
		else vis[u]=cnt,st[++tp]=u;
		if(rt[u]==0)return -inf;
		Val tmp=P[rt[u]].v;
		pop(rt[u]);push(rt[u],-tmp.w);
		return tmp.w+dfs(find(tmp.v));
	}
	#undef inf
	//由于不用存图,这里直接输入了 
	int solve(void){
		int n,m,r;
		scanf("%d%d%d",&n,&m,&r);
		//所有点要都可以到达 r 
		vis[r]=cnt=1;
		for(int i=1;i<=n;++i)
			id[i]=i;
		for(int i=1;i<=m;++i){
			int u,v,w;
			scanf("%d%d%d",&u,&v,&w);
			merge(rt[v],rt[v],newnode(Val(u,w)));
		}
		int ans=0;
		for(int i=1;i<=n;++i){
			if(i!=r&&!vis[i]){
				++cnt;
				int tmp=dfs(i);tp=0;
				if(tmp<0)return -1;//无解 
				ans+=tmp;
			}
		}
		return ans;
	}
}
//KMP
namespace KMP{
	const int maxn=100005;
	int next[maxn];
	void getnext(char*s){
		int n=strlen(s+1);
		next[1]=0;
		for(int i=2;i<=n;++i){
			int j=next[i-1];
			while(j&&s[j+1]!=s[i])j=next[j];
			if(s[j+1]==s[i])next[i]=j+1;
			else next[i]=0;
		}
	}
	void KMP(char*s1,char*s2){
		//Find s2 in s1
		getnext(s2);
		int n=strlen(s1+1),
			m=strlen(s2+1);
		int i=1,j=1;
		while(i<=n){
			while(j>1&&s1[i]!=s2[j])
				j=next[j-1]+1;
			if(s1[i]==s2[j]){
				++i;++j;
				if(j==m+1){
					//Find it!
					printf("%d\n",i-m);
					j=next[j-1]+1;
				}
			}
			else ++i;
		}
		for(int i=1;i<=m;++i)
			printf("%d%c",next[i]," \n"[i==m]);
	}
}
//ACAM
namespace ACAM{
	const int maxn=100005;
	int son[maxn][26],fail[maxn],tot;
	int newnode(void){
		++tot;memset(son[tot],0,sizeof son[tot]);
		fail[tot]=0;return tot;
	}
	void ins(char*s){
		int n=strlen(s+1),now=0;
		for(int i=1;i<=n;++i){
			int o=s[i]-'a';
			if(!son[now][o])
				son[now][o]=newnode();
			now=son[now][o];
		}
	}
	int q[maxn];
	void build(void){
		int fro=0,bac=0;
		for(int i=0;i<26;++i)if(son[0][i])
			fail[q[bac++]=son[0][i]]=0;
		while(fro<bac){
			int u=q[fro++];
			for(int i=0;i<26;++i){
				if(son[u][i])
					fail[q[bac++]=son[u][i]]=son[fail[u]][i];
				//else son[u][i]=son[fail[u][i]];
			}
		}
	}
}
//SA 后缀数组 
namespace SA{
	const int maxn=1000005;
	int rk[maxn],sa[maxn];
	void solve(char*s){
		int n=strlen(s+1);
	}
}
int main(){
	return 0;
}

原文链接: https://www.cnblogs.com/lsq147/p/17020033.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍

    模板集

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/309251

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年2月16日 上午10:58
下一篇 2023年2月16日 上午10:58

相关推荐