考前10模板

dijkstra+优先队列优化

#include<bits/stdc++.h>
using namespace std;
const int N=1e4+10,M=5e5+10;
int n,m,s,bb=1;
int dis[N],vis[N];
struct node{
	int x,y;
	bool operator > (const node & a) const //重载运算符 ,x小才算小的 
	{
		return x>a.x;
	}
};
priority_queue<node,vector<node>,greater<node> > q;//优先队列优化 
int tot=1,head[N],ver[M],edge[M],Next[M];
void add(int x,int y,int z)
{
	ver[++tot]=y;
	edge[tot]=z;
	Next[tot]=head[x];
	head[x]=tot;
}
void dijkstra()
{
	memset(dis,0x3f,sizeof(dis));
	dis[s]=0;
	q.push({dis[s],s});
	while(!q.empty())
	{
		int x=q.top().y;
		q.pop();
		if(vis[x])
			continue;
		vis[x]=1;
		for(int i=head[x];i;i=Next[i])
		{
			int y=ver[i];
			if(!vis[y]&&dis[y]>dis[x]+edge[i])
			{
				dis[y]=dis[x]+edge[i];
				q.push({dis[y],y});
			}	
		}
	}
}
int main()
{
	scanf("%d%d%d",&n,&m,&s);
	for(int i=1;i<=m;i++)
	{
		int u,v,w;
		scanf("%d%d%d",&u,&v,&w);
		add(u,v,w);
	}
	dijkstra();
	for(int i=1;i<=31;i++)
		bb*=2;
	bb-=1;
	for(int i=1;i<=n;i++)
	{
		if(dis[i]!=0x3f3f3f3f)
			printf("%d ",dis[i]);
		else
			printf("%d ",bb);
	}
 	return 0;
}

线段树2

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e5+10;
ll a[N],p;
int n,m;
struct node{
	int l,r;
	ll sum,add=0,mul=1;
}tree[4*N+10];
void push_up(int k)
{
	tree[k].sum=(tree[k<<1].sum+tree[k<<1|1].sum)%p;
}
void push_down(int k)
{
	tree[k<<1].sum=(tree[k<<1].sum*tree[k].mul+(tree[k<<1].r-tree[k<<1].l+1)*tree[k].add)%p;
	tree[k<<1|1].sum=(tree[k<<1|1].sum*tree[k].mul+(tree[k<<1|1].r-tree[k<<1|1].l+1)*tree[k].add)%p;
	tree[k<<1].mul=(tree[k<<1].mul*tree[k].mul)%p;
	tree[k<<1|1].mul=(tree[k<<1|1].mul*tree[k].mul)%p;
	tree[k<<1].add=(tree[k<<1].add*tree[k].mul+tree[k].add)%p;
	tree[k<<1|1].add=(tree[k<<1|1].add*tree[k].mul+tree[k].add)%p;
	tree[k].add=0;
	tree[k].mul=1;
}
void build(int k,int l,int r)
{
	tree[k].l=l;
	tree[k].r=r;
	if(l==r)
	{
		tree[k].sum=a[l]%p;
		return ;
	}
	int mid=(l+r)>>1;
	build(k<<1,l,mid);
	build(k<<1|1,mid+1,r);
	push_up(k);
}
void updateAdd(int k,int l,int r,ll va)
{
	if(l<=tree[k].l&&tree[k].r<=r)
	{
		tree[k].add=(tree[k].add+va)%p;
		tree[k].sum=(tree[k].sum+(tree[k].r-tree[k].l+1)*va)%p;
		return ;
	}
	push_down(k);
	int mid=(tree[k].l+tree[k].r)>>1;
	if(l<=mid)
		updateAdd(k<<1,l,r,va);
	if(r>mid)
		updateAdd(k<<1|1,l,r,va);
	push_up(k);
}
void updateMul(int k,int l,int r,ll va)
{
	if(l<=tree[k].l&&tree[k].r<=r)
	{
		tree[k].add=(tree[k].add*va)%p;
		tree[k].mul=(tree[k].mul*va)%p;
		tree[k].sum=(tree[k].sum*va)%p;
		return ;
	}
	push_down(k);
	int mid=(tree[k].l+tree[k].r)>>1;
	if(l<=mid)
		updateMul(k<<1,l,r,va);
	if(r>mid)
		updateMul(k<<1|1,l,r,va);
	push_up(k);
}
ll query(int k,int l,int r)
{
	if(l<=tree[k].l&&tree[k].r<=r)
		return tree[k].sum%p;
	push_down(k);
	ll ans=0;
	int mid=(tree[k].l+tree[k].r)>>1;
	if(l<=mid)
		ans=(ans+query(k<<1,l,r))%p;
	if(r>mid)
		ans=(ans+query(k<<1|1,l,r))%p;
	return ans%p;
}
int main()
{
	scanf("%d%d%lld",&n,&m,&p);
	for(int i=1;i<=n;i++)
		scanf("%lld",&a[i]);
	build(1,1,n);
	for(int i=1;i<=m;i++)
	{
		int opt;
		scanf("%d",&opt);
		if(opt==1)
		{
			int x,y;
			ll k;
			scanf("%d%d%lld",&x,&y,&k);
			updateMul(1,x,y,k);
		}
		else
		{
			if(opt==2)
			{
				int x,y;
				ll k;
				scanf("%d%lld%lld",&x,&y,&k);
				updateAdd(1,x,y,k);
			}
			else
			{
				if(opt==3)
				{
					int x,y;
					scanf("%d%d",&x,&y);
					printf("%lld\n",query(1,x,y));
				}
			}
		}
		
	}
 	return 0;
}

2-SAT问题(内含tarjan缩点)

#include<bits/stdc++.h>
using namespace std;
const int N=2e6+10;
int n,m;
stack<int> s;
int cut,cnt,instack[N],dfn[N],low[N],sc[N];
int tot=1,head[N],ver[N],Next[N];
void add(int x,int y)
{
	ver[++tot]=y;
	Next[tot]=head[x];
	head[x]=tot;
}
void tarjan(int x)//tarjan找求强连通分量,若x=1与x=0的情况在一个强连通里,则说明无解 
{                 //因为这样x=1与x=0能互相推出,显然不对 
	
	dfn[x]=low[x]=++cnt;
	s.push(x);
	instack[x]=1;
	for(int i=head[x];i;i=Next[i])
	{
		int y=ver[i];
		if(!dfn[y])
			tarjan(y);
		if(instack[y])
			low[x]=min(low[x],low[y]);
	}
	if(dfn[x]==low[x])
	{
		cut++;
		while(true)
		{
			int z=s.top();
			s.pop();
			sc[z]=cut;
			instack[z]=0;
			if(dfn[z]==low[z])
				break;
		}
	}
}
int main()
{
	scanf("%d%d",&n,&m);
	//x表示x=1的情况,x+n表示x=0的情况 
	for(int i=1;i<=m;i++)
	{
		int x1,x2,t1,t2;
		scanf("%d%d%d%d",&x1,&t1,&x2,&t2);
		if(t1&&t2)
		{
			add(x1+n,x2);
			add(x2+n,x1);
		}
		if(!t1&&t2)
		{
			add(x1,x2);
			add(x2+n,x1+n);
		}
		if(t1&&!t2)
		{
			add(x2,x1);
			add(x1+n,x2+n);
		}
		if(!t1&&!t2)
		{
			add(x1,x2+n);
			add(x2,x1+n);
		}
	}
	for(int i=1;i<=2*n;i++)
		if(!dfn[i])
			tarjan(i);
	for(int i=1;i<=n;i++)
	{
		if(sc[i]==sc[i+n])
		{
			printf("IMPOSSIBLE\n");
			return 0;
		}
	}
	printf("POSSIBLE\n");
	for(int i=1;i<=n;i++)
	{
		if(sc[i]<sc[i+n])//找顺序更靠后的方案,因为这样能避免起冲突 
			printf("1");//就是先找逻辑链最末端的,因为这最没问题 
		else
			printf("0");
		printf(" ");
	}
 	return 0;
}

差分约束系统(建模成最短路)

#include<bits/stdc++.h>
using namespace std;
const int N=5e3+10;
int n,m,x[N];
struct node{
	int u,v,w;
};
vector<node> E;
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++)
	{
		int u1,v1,w1;
		scanf("%d%d%d",&u1,&v1,&w1);
		E.push_back({v1,u1,w1});//建反向边,使其符合松弛操作 
	}
	for(int i=1;i<=n;i++)
		x[i]=0x3f3f3f3f;
	x[1]=0;//建模成所有点到1的最短路 
	for(int i=1;i<=n;i++)//bellman-ford松弛,不嫌烦当然可以用spfa优化 
		for(auto [u,v,w]:E)
				x[v]=min(x[v],x[u]+w);
	for(auto [u,v,w]:E)
	{
		if(x[v]>x[u]+w)//n轮松弛后仍然可以松弛,说明有负环,无解 
		{
			printf("NO");
			return 0;
		}
	}
	for(int i=1;i<=n;i++)
	{
		printf("%d ",x[i]);
	}
	return 0;
}

网络最大流(可以顺带解决二分图最大匹配)

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=210,M=5010;
int n,m,s,t;
ll dis[N],edge[M*2]; 
int tot=1,head[N],ver[M*2],Next[M*2],cur[N];
inline void add(int x,int y,int z)
{
	ver[++tot]=y;
	Next[tot]=head[x];
	head[x]=tot;
	edge[tot]=z;
}
inline bool bfs()//判断是否还能増广,并将图分层 
{
	for(int i=1;i<=n;i++)
		cur[i]=head[i];//弧优化 
	memset(dis,0,sizeof(dis));//每次找增广路,记得重新初始化dis 
	queue<int> q;
	q.push(s);
	dis[s]=1;
	while(!q.empty())
	{
		int x=q.front();
		q.pop();
		for(int i=head[x];i;i=Next[i])
		{
			int y=ver[i];
			if(!edge[i]||dis[y])
				continue;
			dis[y]=dis[x]+1;
			if(y==t)
				return true;
			q.push(y);
		}
	}
	return false;
}
inline ll dfs(int x,ll m)
{
	if(x==t)
		return m;
	ll flow=0;
	for(int i=cur[x];i;cur[x]=i=Next[i])//弧优化 
	{
		int y=ver[i];
		if(edge[i]&&dis[y]==dis[x]+1)
		{
			int f=dfs(y,min(m,edge[i]));//一路上流量受路径的最大流量限制 
			edge[i]-=f;
			edge[i^1]+=f;//反向边,使其在后面能够重新获得流出的这部分流量,试着用于找其他增广路 
			m-=f;
			flow+=f;
		}
		if(!m)
			break;//没有剩余流量了,不继续増广 
	}
	if(!flow)
		dis[x]=0;//此点无法増广,将其剪掉 
	return flow;
}
inline ll dinic()
{
	ll flow=0;
	while(bfs())//循环找增广路,直到增广路穷尽 
		flow+=dfs(s,0x7f7f7f7f);
	return flow;
}
int main()
{
	scanf("%d%d%d%d",&n,&m,&s,&t);
	for(int i=1;i<=m;i++)
	{
		int u,v,w;
		scanf("%d%d%d",&u,&v,&w);
		add(u,v,w);
		add(v,u,0);//建反边 
	}
	printf("%lld\n",dinic());
 	return 0;
}

AC自动机二次加强版

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
char ch[N],ch1[N*10];
int cnt,n,Map[N],in[N],ans[N];
queue<int> q;
struct node{
	int ans;
	int flag;
	int fail;
	int son[30];
}trie[N];
void insert(char* s,int num)//字典树的基本插入 
{
	int u=1,l=strlen(s);
	for(int i=0;i<l;i++)
	{
		int v=s[i]-'a';
		if(!trie[u].son[v])
			trie[u].son[v]=++cnt;
		u=trie[u].son[v];
	}
	if(!trie[u].flag)//下面三行为防止有重复的模式串 
		trie[u].flag=num;
	Map[num]=trie[u].flag;
}
void getFail()
{
	for(int i=0;i<26;i++)//让一些fail跳到0的点可以到真正的根节点1去 
		trie[0].son[i]=1;
	q.push(1);
	while(!q.empty())
	{
		int x=q.front();
		q.pop();
		int Fail=trie[x].fail;
		for(int i=0;i<26;i++)
		{
			int v=trie[x].son[i];
			if(!v)
			{
				trie[x].son[i]=trie[Fail].son[i];//没有此节点直接跳到另外的有这个字母的地方 
				continue;
			}
			trie[v].fail=trie[Fail].son[i];
			in[trie[v].fail]++;
			q.push(v);//真实存在的边的另一点才可用于更新 
		}
	}
}
void query(char* s)
{
	int u=1,l=strlen(s);
	for(int i=0;i<l;i++)
	{
		u=trie[u].son[s[i]-'a'];
		trie[u].ans++; 
	}
}
void topu()//拓扑来跳fail指针,防止重复跳,优化的关键 
{
	for(int i=1;i<=cnt;i++)
		if(!in[i])
			q.push(i);
	while(!q.empty())
	{
		int x=q.front();
		q.pop();
		ans[trie[x].flag]=trie[x].ans;
		int v=trie[x].fail;
		in[v]--;
		trie[v].ans+=trie[x].ans;
		if(!in[v])
			q.push(v);
	}
}
int main()
{
	scanf("%d",&n);
	cnt=1;
	for(int i=1;i<=n;i++)
	{
		scanf("%s",ch);
		insert(ch,i);
	}
	getFail();
	scanf("%s",ch1);
	query(ch1);
	topu();
	for(int i=1;i<=n;i++)
		printf("%d\n",ans[Map[i]]);
	return 0;
}

树链剖分

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10; 
int n,m,r,p,a[N];
int tot,head[N],ver[N*2],Next[N*2];
int cnt,id[N],fa[N],son[N],dep[N],sz[N],top[N],wa[N];
struct node{
	int le,ri;
	int sum1,tag;
}tree[4*N+5];
void build(int k,int l,int r){
	tree[k].le=l;tree[k].ri=r;
	if(l==r){
		tree[k].sum1=wa[l];
		return ;
	}
	int mid=(l+r)>>1;
	build(k<<1,l,mid);
	build(k<<1|1,mid+1,r);
	tree[k].sum1=tree[k<<1].sum1+tree[k<<1|1].sum1;
}
void lazy_tag(int k){
	if(tree[k].tag!=0){
		tree[k<<1].tag+=tree[k].tag;
		tree[k<<1|1].tag+=tree[k].tag;
		tree[k<<1].sum1+=tree[k].tag*(tree[k<<1].ri-tree[k<<1].le+1);
		tree[k<<1|1].sum1+=tree[k].tag*(tree[k<<1|1].ri-tree[k<<1|1].le+1);
		tree[k].tag=0;
	}
}
void change(int k,int l,int r,int w){
	if(l<=tree[k].le&&r>=tree[k].ri){
		tree[k].tag+=w;
		tree[k].sum1+=w*(tree[k].ri-tree[k].le+1);
		return ;
	}
	lazy_tag(k);
	int mid=(tree[k].le+tree[k].ri)>>1;
	if(l<=mid)change(k<<1,l,r,w);
	if(r>mid)change(k<<1|1,l,r,w);
	tree[k].sum1=(tree[k<<1].sum1+tree[k<<1|1].sum1)%p;
}
int query(int k,int l,int r){
	if(l<=tree[k].le&&r>=tree[k].ri){
		return tree[k].sum1%p;
	}
	lazy_tag(k);
	int mid=(tree[k].le+tree[k].ri)>>1;
	int ans=0;
	if(l<=mid)ans+=query(k<<1,l,r);
	if(r>mid)ans+=query(k<<1|1,l,r);
	ans=ans%p;
	return ans;
}
void add(int x,int y)
{
	ver[++tot]=y;
	Next[tot]=head[x];
	head[x]=tot;
}
void dfs1(int x,int f,int d)
{
	fa[x]=f;
	dep[x]=d;
	sz[x]=1; 
	for(int i=head[x];i;i=Next[i])
	{
		int y=ver[i];
		if(y==f)
			continue;
		dfs1(y,x,d+1);
		sz[x]+=sz[y];
		if(sz[y]>sz[son[x]])
			son[x]=y;
	}
}
void dfs2(int x,int topf)
{
	id[x]=++cnt;
	wa[cnt]=a[x];
	top[x]=topf;
	if(!son[x])
		return ;
	dfs2(son[x],topf);
	for(int i=head[x];i;i=Next[i])
	{
		int y=ver[i];
		if(y==fa[x]||y==son[x])
			continue;
		dfs2(y,y);
	}
}
int queryRange(int x,int y)
{
	int ans=0;
	while(top[x]!=top[y])
	{
		if(dep[top[x]]<dep[top[y]])
			swap(x,y);
		int res=query(1,id[top[x]],id[x]);
		ans+=res;
		ans%=p;
		x=fa[top[x]];
	}
	if(dep[x]>dep[y])
		swap(x,y);
	int res=query(1,id[x],id[y]);
	ans+=res;
	return ans%p;
}
void updateRange(int x,int y,int z)
{
	while(top[x]!=top[y])
	{
		if(dep[top[x]]<dep[top[y]])
			swap(x,y);
		change(1,id[top[x]],id[x],z);
		x=fa[top[x]];
	}
	if(dep[x]>dep[y])
		swap(x,y);
	change(1,id[x],id[y],z);
}
int main()
{
	scanf("%d%d%d%d",&n,&m,&r,&p);
	for(int i=1;i<=n;i++)
		scanf("%d",&a[i]);
	for(int i=1;i<n;i++)
	{
		int x,y;
		scanf("%d%d",&x,&y);
		add(x,y);
		add(y,x);
	}
	dfs1(r,0,1);
	dfs2(r,r);
	build(1,1,cnt);
	for(int i=1;i<=m;i++)
	{
		int opt;
		scanf("%d",&opt);
		if(opt==1)
		{
			int x,y,z;
			scanf("%d%d%d",&x,&y,&z);
			updateRange(x,y,z);
		}
		if(opt==2)
		{
			int x,y;
			scanf("%d%d",&x,&y);
			printf("%d\n",queryRange(x,y)%p);
		}
		if(opt==3)
		{
			int x,y;
			scanf("%d%d",&x,&y);
			change(1,id[x],id[x]+sz[x]-1,y);
		}
		if(opt==4)
		{
			int x;
			scanf("%d",&x); 
			printf("%d\n",query(1,id[x],id[x]+sz[x]-1)%p);
		}
	}
	return 0;

二分图最大匹配

#include<bits/stdc++.h>
using namespace std;
const int N=510,E=5e4+10;
int n,m,e,ans,vis[N],mch[N];
int tot,head[N],from[E],ver[E],Next[E];
void add(int x,int y)
{
	ver[++tot]=y;
	from[tot]=x;
	Next[tot]=head[x];
	head[x]=tot;
}
bool dfs(int u,int tag)
{
	if(vis[u]==tag)
		return false;
	vis[u]=tag;
	for(int i=head[u];i;i=Next[i])
	{
		int y=ver[i];
		if(!mch[y]||dfs(mch[y],tag))
		{
			mch[y]=u;
			return true;
		}
	}
	return false;
}
int main()
{
	scanf("%d%d%d",&n,&m,&e);
	for(int i=1;i<=e;i++)
	{
		int u,v;
		scanf("%d%d",&u,&v);
		add(u,v);
	}
	for(int i=1;i<=n;i++)
		if(dfs(i,i))
			ans++;
	printf("%d\n",ans);
	return 0;
}

高精度

#include<bits/stdc++.h>
using namespace std;
const int N=2010;
string ch1,ch2;
int a[N],b[N],c[N],x;
void add(string aa,string bb){
	if(bb.size()>aa.size())
	{
		add(bb,aa);
		return ;
	}
	int l=aa.size();
	for(int i=aa.size()-1;i>=0;i--)a[aa.size()-i-1]=aa[i]-'0';
	for(int i=bb.size()-1;i>=0;i--)b[bb.size()-i-1]=bb[i]-'0';
	for(int i=0;i<l;i++)
	{
		x=a[i]+b[i];
		c[i]+=x;
		c[i+1]=c[i]/10;
		c[i]=c[i]%10;
	}
	if(c[l]==0)l--;
	for(int i=l;i>=0;i--)cout<<c[i];
}
int main(){
	cin>>ch1>>ch2;
	add(ch1,ch2);
	return 0;
}

kmp

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

中国剩余定理

#include<bits/stdc++.h>
using namespace std;
const int N=15;
int n,a[N],b[N];
long long ans,M=1,Mi[N],x,y;
void exgcd(long long a,long long b)
{
	if(b==0)
	{
		x=1;
		y=0;
		return ;
	}
	exgcd(b,a%b);
	long long t=x;
	x=y;
	y=t-a/b*y;
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%d%d",&a[i],&b[i]);
		M*=a[i];
	}
	for(int i=1;i<=n;i++)
	{
		Mi[i]=M/a[i];
		exgcd(Mi[i],a[i]);
		ans+=b[i]*Mi[i]*((x%a[i]+a[i])%a[i]);
	}
	cout<<ans%M<<endl;
	return 0;
}
posted @ 2022-08-26 09:20  K_layna  阅读(26)  评论(0)    收藏  举报