medal-dreams

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

快读

inline int read()
{
	int x = 0;
	int flag = 1;
	char c = getchar();
	while(!isdigit(c))
	{
		if(c == '-')
		flag = -1;
		c = getchar();
	}
	while(isdigit(c))
	{
		x = x * 10 + (c - '0');
		c = getchar();
	}
	return x * flag;
}//快读
template<typename T> void read(T&x)
{
	char c;int sign = 1;x = 0;
	// 判断是否是负数,以及去掉前面多余的字符
	do { c = getchar(); if(c == '-') sign = -1; }while(!isdigit(c)); 
	do { x = x * 10 + c - '0'; c = getchar(); }while(isdigit(c));
	x *= sign;
}

快出

inline void put(long long d)
{
	if(d < 0)
	putchar('-'),d = -d;
	if(d > 9) put(d / 10);
    putchar((d % 10) + '0');
}

dp

LIS 和 LCS

最长上升子序列(LIS)

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 50;
long long s[N],top;
long long a[N],ans,n,ma = -1;
int main()
{
	cin >> n;
	for(int i = 1;i <= n;i ++)
	cin >> a[i];
	for(int i = 1;i <= n;i ++)
	{
		s[i] = 1;
		for(int j = 1;j < i;j ++)
		if(a[j] < a[i])
		s[i] = max(s[j] + 1,s[i]);
		ma = max(s[i],ma);
	}
	cout << ma << endl;
}

最长上升子序列(LIS)(已优化)

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 50;
long long s[N],top;
long long a[N],ans,n;
int left_boundary(int x)
{
	int l = 1,r = top;
	while(l <= r)
	{
		int mid = l + (r - l) / 2;
		if(s[mid] >= x)
		r = mid - 1;
		else
		l = mid + 1;
	}
	return l;
}
int main()
{
	cin >> n;
	for(int i = 1;i <= n;i ++)
	cin >> a[i];
	s[++ top] = a[1];
	for(int i = 2;i <= n;i ++)
	{
		if(s[top] >= a[i])
			s[left_boundary(a[i])] = a[i];
		else
		s[++ top] = a[i];
	}
	cout << top << endl;
}

最长公共子序列(LCS)(已优化)

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+66;
int dp[N],a[N],b[N],c[N];
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
	int n;
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
		c[a[i]]=i;
	}
	for(int i=1;i<=n;i++)
	{
		cin>>b[i];
	}
	dp[1]=c[b[1]];
	int k=1;
	for(int i=2;i<=n;i++)
	{
		if(c[b[i]]>dp[k])
		{
			k++;
			dp[k]=c[b[i]];
		}
		else
		{
			dp[lower_bound(dp+1,dp+1+k,c[b[i]])-dp]=c[b[i]];
		}
	}
	cout<<k<<endl;
	return 0;
}

背包问题

01背包

#include<bits/stdc++.h>
using namespace std;
const int N=1100;
int dp[N],v[N],w[N];
int n,s;
int main()
{
	memset(dp,0,sizeof(dp));
	cin>>n>>s;
	for(int i=1;i<=n;i++)
	{
		cin>>w[i]>>v[i];
	}
	for(int i=1;i<=n;i++)
	{
		for(int j=s;j>=w[i];j--)
		{
			dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
		}
	}
	cout<<dp[s];
	return 0;
}

完全背包

#include<bits/stdc++.h>
using namespace std;
const int N=1100;
int v[N],w[N],dp[N];
int main()
{
	int n,s;
	cin>>n>>s;
	for(int i=1;i<=n;i++)
	{
		cin>>w[i]>>v[i];
		for(int j=w[i];j<=s;j++)
		{
			dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
		}
	}
	cout<<dp[s];
 } 

多重背包

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 21000;
const int M = 2100;
int dp[M],w[N],v[N];
int wi,vi,shu,k,q;
int main()
{
	int n,c;
	cin>>n>>c;
	for(int i=1;i<=n;i++)
	{
		cin>>wi>>vi>>shu;
		k = 1;
		while(shu>=k)
		{
			q ++;
			v[q] = vi*k;
			w[q] = wi*k;
			shu -= k;
			k *= 2;
		}
		if(shu>0)
		{
			q++;
			v[q] = vi*shu;
			w[q] = wi*shu;
		}
		
	}
	for(int i=1;i<=q;i++)
	for(int j=c;j>=w[i];j--)
	dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
	cout<<dp[c];
	return 0;
}

混合背包

#include<bits/stdc++.h> 
using namespace std;
const int N = 21000;
const int M = 21000;
int v[N],w[N],dp[M],s[N];
int vi,wi,si;
int k = 0;
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
	int n,c;
	cin >> n >> c;
	for(int i = 1;i <= n;i ++)
	{
		cin >> wi >> vi >> si;
		if(si > 0)
		{
			int t=1;
			while(t<=si)
			{
				k ++;
				w[k] = t * wi;
				v[k] = t * vi;
				s[k] = -1;
				si = si - t;
				t *= 2;
			}
			if(si)
			{
				k ++;
				w[k] = si * wi;
				v[k] = si * vi;
				s[k] = -1;
			}
		}
		else
		{
			k ++;
			v[k] = vi;
			w[k] = wi;
			s[k] = si;
		}
	}
	for(int  i = 1;i <= k;i ++)
	{
		if(s[i] == -1)
		for(int j = c;j >= w[i];j --)
		dp[j] = max(dp[j],dp[j - w[i]] + v[i]);
		else
		for(int j = w[i];j <= c;j ++)
		dp[j] = max(dp[j],dp[j - w[i]] + v[i]);
	}
	cout << dp[c];
	return 0;
}

二维费用背包

#include<bits/stdc++.h> 
using namespace std;
const int N = 1050;
const int M = 1000;
int v,w,dp[M][M],s;
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
	int vk,wk,n;
	cin>>n>>vk>>wk;
	for(int i = 1;i <= n;i ++)
	{
		cin >>v >>w >>s;
		for(int j = vk;j >= v;j --)
			for(int k = wk;k >= w;k --)
			dp[j][k]=max(dp[j][k],dp[j - v][k - w] + s);
	}
		
	cout<<dp[vk][wk];
	return 0;
}

分组背包

#include<bits/stdc++.h>
using namespace std;
const int N = 2100;
int dp[N];
inline int read()
{
	int x = 0;
	int flag = 1;
	char c = getchar();
	while(!isdigit(c))
	{
		if(c == '-')
		flag = -1;
		c = getchar();
	}
	while(isdigit(c))
	{
		x = x * 10 + (c - '0');
		c = getchar();
	}
	return x * flag;
}//快读
int n,m;
struct ccs{
	int w,v,group;
}a[N];
int main()
{
	vector<pair<int,pair<int,int> > > o;
	//m[i].first -> group m[i].first.first -> v second -> w
	int m = read(),n = read();
	for(int i = 1;i <= n;i ++)
		a[i].w = read(),a[i].v = read(),a[i].group = read();
	for(int i = 1;i <= n;i ++)
	{
		bool p = 0;
		pair<int,int> q;
		for(auto s:o)
		{
			if(s.first == a[i].group)
			{
				q.first = s.second.first;
				q.second = s.second.second;
				p = 1;
			}
		}
		for(int j = m;j >= a[i].w;j --)
		{
			if(p)
			{
				if(j >= q.second)
					dp[j] = max(dp[j],dp[j - a[i].w] + a[i].v - q.first);
				else
					dp[j] = max(dp[j],dp[j - a[i].w] + a[i].v);
			}
			else
			{
				dp[j] = max(dp[j],dp[j - a[i].w] + a[i].v);
				o.push_back(make_pair(a[i].group,make_pair(a[i].v,a[i].w)));
			}
		 } 
	}
		
	cout << dp[m];
	return 0;
}

图论

单源最短路

SPFA

#include<bits/stdc++.h>
using namespace std;
const int N = 5e5+50,M=5e5+50;
int n,m,s;
int head[N],nxt[M],to[M],w[M],tot;
void add(int x,int y,int val)
{
	to[tot]=y;
	nxt[tot]=head[x];
	w[tot]=val;
	head[x]=tot++;
}
long long d[N];//表示从s出发到x节点的最短路长度 
int vis[N];//vis[x]表示是否选取过x这个节点,更新最短路 
queue<int> q;
void dij()
{
	int x; 
	for(int i=0;i<=n;i++)
	{
		d[i]=INT_MAX;
	}
	d[s]=0;
	q.push(s);
	while(!q.empty())
	{
		int x=q.front();q.pop();vis[x] = 0;
		for(int i=head[x];~i;i=nxt[i])
		{
			if(d[to[i]]>d[x]+w[i])
			{
				d[to[i]]=d[x]+w[i];
  				if(!vis[to[i])
                {
                     vis[to[i]] = 1;
                     q.push(to[i]);
                }
			}
		}
	}
}
int main()
{
	memset(head,-1,sizeof(head));
	cin>>n>>m>>s;
	for(int i=1;i<=m;i++)
	{
		int x,y,c;
		cin>>x>>y>>c;
		add(x,y,c);
	}
	dij();
	for(int i=1;i<=n;i++)
	{
		cout<<d[i]<<" ";
	}
	return 0; 
 }

dijkstra非堆优化

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+50,M=5e5+50;
int n,m,s;
int head[N],nxt[M],to[M],w[M],tot;
void add(int x,int y,int val)
{
	to[tot]=y;
	nxt[tot]=head[x];
	w[tot]=val;
	head[x]=tot++;
}
long long d[N];//表示从s出发到x节点的最短路长度 
int vis[N];//vis[x]表示是否选取过x这个节点,更新最短路 
void dij(int x)
{
	for(int i=0;i<=n;i++)
		d[i]=INT_MAX;
	d[x]=0;
	int y;
	for(int i=1;i<n;i++)
	{
		y=0;
		for(int j=1;j<=n;j++)
			if(!vis[j]&&d[j]<d[y])
				y=j;
		vis[y]=1;
		for(int j=head[y];~j;j=nxt[j])
			if(d[to[j]]>d[y]+w[j])
				d[to[j]]=d[y]+w[j];
	}
}
int main()
{
	memset(head,-1,sizeof(head)/4);
	cin>>n>>m>>s;
	for(int i=1;i<=m;i++)
	{
		int x,y,c;
		cin>>x>>y>>c;
		add(x,y,c);
	}
	dij(s);
	for(int i=1;i<=n;i++)
		cout<<d[i]<<" ";
	return 0; 
}

dijkstra 堆优化

#include<bits/stdc++.h>
using namespace std; 
const int N = 5e5+66;
typedef long long LL;
int n,s,m;
int head[N],to[N],nxt[N],w[N],tot;
LL d[N];
bool vis[N];
void add(int x,int y,int v)
{
	to[tot] = y;
	nxt[tot] = head[x];
	w[tot] = v;
	head[x] = tot ++;
}
priority_queue<pair<LL,int> > q;
void dij()
{
	d[s] = 0;
	q.push(make_pair(-d[s],s));
	while(!q.empty())
	{
		int x = q.top().second;
		q.pop();
		if(vis[x])
		continue;
		vis[x] = 1;
		for(int i = head[x];~i;i = nxt[i])
			if(d[to[i]] > d[x] + w[i])
			{
				d[to[i]] = d[x] + w[i];
				q.push(make_pair(-d[to[i]],to[i]));
			}
	}
}
signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
	memset(head,-1,sizeof(head));
	cin >> n >> m >> s;
	int x,y,k;
	for(int i = 1;i <= m;i ++)
	{
		cin >> x >> y >> k;
		add(x,y,k);
	}
	for(int i = 1;i <= n;i ++)
	d[i] = INT_MAX;
	dij();
	for(int j = 1;j <= n;j ++)
		cout << d[j] << " ";
	return 0;	
}

floyd

#include<bits/stdc++.h>
using namespace std;
const int N=505;
int n,m,dp[N][N];
int main()
{
	memset(dp,0x3f,sizeof(dp));
	cin>>n>>m;
	for(int i=1;i<=m;i++)
	{
		int x,y,w;
		cin>>x>>y>>w;
		dp[x][y]=min(dp[x][y],w);//可能存在重边 
		dp[y][x]=min(dp[y][x],w);
	}
	for(int i=1;i<=n;i++)
	{
		dp[i][i]=0;
	}
	for(int k=1;k<=n;k++)
	{
		for(int i=1;i<=n;i++)
		{
			for(int j=1;j<=n;j++)
			{
				dp[i][j]=min(dp[i][j],dp[i][k]+dp[k][j]);
			}
		}
	}
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++)
		{
			cout<<dp[i][j]<<" ";
		}
		cout<<endl;
	}
	return 0;
}

johnson 全源最短路

板子题

#include<bits/stdc++.h>
using namespace std;
#define int long long
template<typename T> void read(T &x)
{
	x = 0;int f = 1;char c;
	do{c = getchar();if(c == '-') f = -1;}while(!isdigit(c));
	do{x = x * 10 + c - '0';c = getchar();}while(isdigit(c));
	x *= f;
}
const int N = 3e3 + 10;
vector<pair<int,int> > tu[N];
bool vis[N];
int f[N][N],h[N],d[N],n,m,ans[N],ru[N];
inline bool spfa()
{
	for(int i = 1;i <= n;i ++) h[i] = 1e9;
	h[0] = 0;
	queue<int> q;
	vis[0] = true;
	q.push(0);
	while(!q.empty())
	{
		int x = q.front();q.pop();
		vis[x] = false;
		for(auto i : tu[x])
			if(h[i.first] > h[x] + i.second)
			{
				h[i.first] = h[x] + i.second;
				if(!vis[i.first])
				{
					vis[i.first] = true;
					q.push(i.first);
					ru[i.first] ++;
					if(ru[i.first] == n + 1) return false;
				}
			}
	}
	for(int i = 1;i <= n;i ++)
		for(auto &k : tu[i])
			k.second += h[i] - h[k.first];
	return true;
}
void dijkstra(int b)
{
	memset(vis,false,sizeof(vis));
	for(int i = 1;i <= n;i ++) d[i] = 1e9;
	d[b] = 0;
	priority_queue<pair<int,int> > di;
	di.push(make_pair(-d[b],b));
	while(!di.empty())
	{
		int t = di.top().second;di.pop();
		if(vis[t]) continue;vis[t] = 1;
		for(auto i : tu[t])
			if(d[i.first] > d[t] + i.second)
			{
				d[i.first] = d[t] + i.second;
				di.push(make_pair(-d[i.first],i.first));
			}
//		for(int i = 1;i <= n;i ++)	f[b][i] = d[i] + h[i] - h[b];
	}
}
signed main()
{
	read(n),read(m);
	for(int i = 1;i <= m;i ++)
	{
		long long u,v,val;
		read(u),read(v),read(val);
		tu[u].push_back(make_pair(v,val));
	}
	for(int i = 1;i <= n;i ++)
		tu[0].push_back(make_pair(i,0));
	if(!spfa()) {cout << -1; return 0;}
	for(int i = 1;i <= n;i ++)
	{
		int ans = 0;
		dijkstra(i);
		for(int j = 1;j <= n;j ++)
		{
			if(d[j] == 1e9) ans += j * 1e9;
			else ans += j * (d[j] + h[j] - h[i]);
		}
		cout << ans << endl;
	}
		
	return 0;
}

非板子

#include<bits/stdc++.h>
using namespace std;
#define int long long
template<typename T> void read(T &x)
{
	x = 0;int f = 1;char c;
	do{c = getchar();if(c == '-') f = -1;}while(!isdigit(c));
	do{x = x * 10 + c - '0';c = getchar();}while(isdigit(c));
	x *= f;
}
const int N = 1e3 + 10;
vector<pair<int,int> > tu[N];
bool vis[N];
int f[N][N],h[N],d[N],n,m,ans[N],ru[N];
inline bool spfa()
{
	for(int i = 1;i <= n;i ++) h[i] = 1e9;
	h[0] = 0;
	queue<int> q;
	vis[0] = true;
	q.push(0);
	while(!q.empty())
	{
		int x = q.front();q.pop();
		vis[x] = false;
		for(auto i : tu[x])
			if(h[i.first] > h[x] + i.second)
			{
				h[i.first] = h[x] + i.second;
				if(!vis[i.first])
				{
					vis[i.first] = true;
					q.push(i.first);
					ru[i.first] ++;
					if(ru[i.first] == n + 1) return false;
				}
			}
	}
	for(int i = 1;i <= n;i ++)
		for(auto &k : tu[i])
			k.second += h[i] - h[k.first];
	return true;
}
void dijkstra(int b)
{
	memset(vis,false,sizeof(vis));
	for(int i = 1;i <= n;i ++) d[i] = 1e9;
	d[b] = 0;
	priority_queue<pair<int,int> > di;
	di.push(make_pair(-d[b],b));
	while(!di.empty())
	{
		int t = di.top().second;di.pop();
		if(vis[t]) continue;vis[t] = 1;
		for(auto i : tu[t])
			if(d[i.first] > d[t] + i.second)
			{
				d[i.first] = d[t] + i.second;
				di.push(make_pair(-d[i.first],i.first));
			}
		for(int i = 1;i <= n;i ++)	f[b][i] = d[i] + h[i] - h[b];
	}
}
signed main()
{
	read(n),read(m);
	for(int i = 1;i <= m;i ++)
	{
		long long u,v,val;
		read(u),read(v),read(val);
		tu[u].push_back(make_pair(v,val));
	}
	for(int i = 1;i <= n;i ++)
		tu[0].push_back(make_pair(i,0));
	if(!spfa()) {cout << -1; return 0;}
	for(int i = 1;i <= n;i ++)
		dijkstra(i);
	for(int i = 1;i <= n;i ++)
		for(int j = 1;j <= n;j ++)
			cout << f[i][j] << (j == n ? '\n' : ' ');
	return 0;
}

tarjan(我爱你)

求强连通分量

#include<bits/stdc++.h>
using namespace std;
template<typename T> inline void rd(T &x)
{
	x = 0;char c;int f = 1;
	do{c = getchar();if(c == '-') f = -1;}while(!isdigit(c));
	do{x = x * 10 + c - '0';c = getchar();}while(isdigit(c));
	x *= f;
}
const int N = 1e6 + 66;
int nxt[N],head[N],to[N],dfn[N],low[N],vis[N],color[N];
stack<int> s;
int n,m,deep = 0,tot,clol;
void add(int x,int y)
{
	nxt[tot] = head[x];
	to[tot] = y;
	head[x] = tot ++;
}
void tarjan(int u)
{
	dfn[u] = low[u] = ++ deep;vis[u] = 1;s.push(u);
	for(int i = head[u];~i;i = nxt[i])
	{
		int v = to[i];
		if(!dfn[v])
		{
			tarjan(v);
			low[u] = min(low[u],low[v]);
		}
		else if(vis[v])
			low[u] = min(low[u],dfn[v]);
	}
	if(dfn[u] == low[u])
	{
		color[u] = ++clol;
		vis[u] = 0;
		while(s.top() != u)
		{
			color[s.top()] = clol;
			vis[s.top()] = 0;
			s.pop();
		}
		s.pop();
	}
}
int main()
{
	memset(head,-1,sizeof(head));
	rd(n),rd(m);
	while(m --)
	{
		int x,y;
		rd(x),rd(y);
		add(x,y);
	}
	for(int i = 1;i <= n;i ++)
		if(!dfn[i])
			tarjan(i);
	cout << clol << endl;
	for(int i = 1;i <= n;i ++)
	{
		if(!vis[i])
		{
			for(int j = i;j <= n;j ++)
				if(color[j] == color[i]) printf("%d ",j),vis[j] = 1;
			putchar('\n');
		}

	}
	return 0;
}

割点

#include<bits/stdc++.h>
using namespace std;
template<typename T> inline void rd(T &x)
{
	x = 0;char c;int f = 1;
	do{c = getchar();if(c == '-') f = -1;}while(!isdigit(c));
	do{x = x * 10 + c - '0';c = getchar();}while(isdigit(c));
	x *= f;
}
const int N = 1e6 + 66;
int nxt[N],head[N],to[N],dfn[N],low[N];
bool vis[N],color[N];
int n,m,deep = 0,tot,clol;
void add(int x,int y)
{
	nxt[tot] = head[x];
	to[tot] = y;
	head[x] = tot ++;
}
void tarjan(int u,int fa)
{
	dfn[u] = low[u] = ++ deep;vis[u] = 1;
	int child = 0;
	for(int i = head[u];~i;i = nxt[i])
	{
		int v = to[i];
		if(!vis[v])
		{
			child ++;
			tarjan(v,u);
			low[u] = min(low[u],low[v]);
			if(fa != u && low[v] >= dfn[u] && !color[u])
			{
				color[u] = 1;
				clol ++;
			}
		}
		else if(v != fa)
			low[u] = min(low[u],dfn[v]);
	}
	if(fa == u && child >= 2 && !color[u])
	{
		color[u] = 1;
		clol ++;
	}
}
int main()
{
	memset(head,-1,sizeof(head));
	rd(n),rd(m);
	while(m --)
	{
		int x,y;
		rd(x),rd(y);
		add(x,y);
		add(y,x);
	}
	for(int i = 1;i <= n;i ++)
		if(!vis[i])
			tarjan(i,i);
	cout << clol << endl;
	for(int i = 1;i <= n;i ++)
		if(color[i]) cout << i << " ";
	return 0;
}

割边(无重边)

#include<bits/stdc++.h>
using namespace std;
template<typename T> inline void rd(T &x)
{
	x = 0;char c;int f = 1;
	do{c = getchar();if(c == '-') f = -1;}while(!isdigit(c));
	do{x = x * 10 + c - '0';c = getchar();}while(isdigit(c));
	x *= f;
}
const int N = 1e6 + 66;
int nxt[N],head[N],to[N],dfn[N],low[N],father[N];
bool vis[N],color[N];
int n,m,deep = 0,tot,clol;
set<pair<int,int> > s;
void add(int x,int y)
{
	nxt[tot] = head[x];
	to[tot] = y;
	head[x] = tot ++;
}
void tarjan(int u,int fa)
{
	father[u] = fa;
	dfn[u] = low[u] = ++ deep;vis[u] = 1;
	for(int i = head[u];~i;i = nxt[i])
	{
		int v = to[i];
		if(!vis[v])
		{
			tarjan(v,u);
			low[u] = min(low[u],low[v]);
			if(low[v] > dfn[u])
			{
				color[v] = 1;
				clol ++;
			}
		}
		else if(v != fa)
			low[u] = min(low[u],dfn[v]);
	}
}
int main()
{
	memset(head,-1,sizeof(head));
	rd(n),rd(m);
	while(m --)
	{
		int x,y;
		rd(x),rd(y);
		add(x,y);
		add(y,x);
	}
	for(int i = 1;i <= n;i ++)
		if(!vis[i])
			tarjan(i,i);
	for(int i = 1;i <= n;i ++)
		if(color[i]) 
			s.insert({min(father[i],i),max(father[i],i)});
	for(auto v:s)
	{
		cout << v.first << " " << v.second << endl;
	}
	return 0;
}

割边(有重边)

#include<bits/stdc++.h>
using namespace std;
template<typename T> inline void rd(T &x)
{
	x = 0;char c;int f = 1;
	do{c = getchar();if(c == '-') f = -1;}while(!isdigit(c));
	do{x = x * 10 + c - '0';c = getchar();}while(isdigit(c));
	x *= f;
}
const int N = 1e6 + 66;
int nxt[N],head[N],to[N],dfn[N],low[N],father[N];
bool vis[N],color[N];
int n,m,deep = 0,tot,clol;
set<pair<int,int> > s;
void add(int x,int y)
{
	nxt[tot] = head[x];
	to[tot] = y;
	head[x] = tot ++;
}
void tarjan(int u,int fa)
{
	bool f = 0;
	father[u] = fa;
	dfn[u] = low[u] = ++ deep;vis[u] = 1;
	for(int i = head[u];~i;i = nxt[i])
	{
		int v = to[i];
		if(!vis[v])
		{
			tarjan(v,u);
			low[u] = min(low[u],low[v]);
			if(low[v] > dfn[u])
			{
				color[v] = 1;
				clol ++;
			}
		}
		else
		{
			if(v != fa || f) low[u] = min(low[u],dfn[v]);
			else f = 1;
		} 
	}
}
int main()
{
	memset(head,-1,sizeof(head));
	rd(n),rd(m);
	while(m --)
	{
		int x,y;
		rd(x),rd(y);
		add(x,y);
		add(y,x);
	}
	for(int i = 1;i <= n;i ++)
		if(!vis[i])
			tarjan(i,i);
	for(int i = 1;i <= n;i ++)
		if(color[i]) 
			s.insert({min(father[i],i),max(father[i],i)});
	for(auto v:s)
	{
		cout << v.first << " " << v.second << endl;
	}
	return 0;
}

最小生成树

kruskal

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+50,M=5e5+50;
int n,m,su,sz[N];
struct NN{
	int u,v,w;
	bool operator <(NN k) const
	{
		return w<k.w;
	}
}e[M];
int p[N];
int find(int x)
{
	return p[x]==x?x:p[x]=find(p[x]);
}//查找祖先 
void kruskal()
{
	sort(e+1,e+1+m);//排序 
	for(int i=1;i<=n;i++)
	{
		p[i]=i;//每个点一个子树,根都是自己 
		sz[i]=1;
	}//并查集 
	for(int i=1;i<=m;i++)
	{
		int x=find(e[i].u);
		int y=find(e[i].v);
		if(x==y) 
		continue;
		p[x]=y;//合并 
		su+=e[i].w;
		sz[y]+=sz[x];
	}
}
int main()
{
	cin>>n>>m;
	for(int i=1;i<=m;i++)
		cin>>e[i].u>>e[i].v>>e[i].w;
	kruskal();
	if(sz[find(1)]!=n)
		cout<<"orz";
	else
	cout<<su;	
	return 0; 
 }

prim(未优化)

#include<bits/stdc++.h>
using namespace std;
const int N = 5e3 + 66,INF = 0x3f3f3f3f; 
vector<pair<int,int> > G[N];
int d[N],n,m,ans;
bool vis[N];
void prim()
{
	memset(d,0x3f,sizeof(d));
	memset(vis,0,sizeof(vis));
	d[1] = 0;
	for(int i = 1;i < n;i ++)
	{
		int x = 0;
		for(int j = 1;j <= n;j ++)
			if(!vis[j] && (x == 0 || d[j] < d[x]))
				x = j;
		vis[x] = 1;
		for(auto v:G[x])
			if(!vis[v.first])
				d[v.first] = min(d[v.first],v.second);
	}
}
int main()
{
	cin >> n >> m;
	for(int i = 1;i <= m;i ++)
	{
		int x,y,z;
		cin >> x >> y >> z;
		G[x].push_back(make_pair(y,z));
		G[y].push_back(make_pair(x,z));
	}
	prim();
	for(int i = 2;i <= n;i ++)
	if(d[i] != INF)
		ans += d[i];
	else
	{
		cout << "orz" << endl;
		return 0;
	}
	cout << ans << endl; 
	return 0;
}

prim

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+50,M=5e5+50;
int n,m,s;
int head[N],nxt[M],to[M],w[M],tot;
void add(int x,int y,int val)
{
	to[tot]=y;
	nxt[tot]=head[x];
	w[tot]=val;
	head[x]=tot++;
}
long long d[N],su; 
int vis[N];//vis[x]表示是否选取过x这个节点,更新最短路 
priority_queue<pair<long long,int> >q;
void prim()
{
	int x; 
	for(int i=0;i<=n;i++)
		d[i]=INT_MAX;
	d[1]=0;
	q.push(make_pair(-d[1],1));
	for(int i=1;i<=n;i++)
	{
		while(!q.empty()&&vis[q.top().second])
			q.pop();
		if(q.empty())
		{
			su=-1;
			break;
		}
		x=q.top().second;
		q.pop();
		vis[x]=1;su+=d[x];
		for(int j=head[x];~j;j=nxt[j])
			if(d[to[j]]>w[j])
			{
				d[to[j]]=w[j];
			    q.push(make_pair(-d[to[j]],to[j]));
			}
	}
}
int main()
{
	memset(head,-1,sizeof(head));
	cin>>n>>m;
	for(int i=1;i<=m;i++)
	{
		int x,y,c;
		cin>>x>>y>>c;
		add(x,y,c);
		add(y,x,c);
	}
	prim();
	if(su==-1)
	{
		cout<<"orz";
		return 0;
	}
	cout<<su;
	return 0; 
 }

字符串

KMP

#include<bits/stdc++.h>
using namespace std;
inline int read()
{
	int x = 0,fl = -1;
	char c = getchar();
	while(!isdigit(c))
	{
		if(c == '-')
			fl = -1;
		c = getchar();
	}
	while(isdigit(c))
	{
		x = x * 10 + c - '0';
		c = getchar();
	}
	return x * fl;
}
const int N = 1e6 + 66;
char a[N],b[N];
int ne[N];
int main()
{
	cin >> a + 1 >> b + 1;
	ne[1] = 0;
	int n = strlen(b + 1),m = strlen(a + 1);
	for(int i = 2,j = 0;i <= n;i ++)
	{
		while(j > 0 && b[i] != b[j + 1]) j = ne[j];
		if(b[i] == b[j + 1]) j ++;
		ne[i] = j;
	}
	for(int i = 1,j = 0;i <= m;i ++)
	{
		while(j > 0 && (j == n || a[i] != b[j + 1])) j = ne[j];
		if(a[i] == b[j + 1]) j ++;
		if(j == n) cout << (i - n + 1) << endl;
	}
	for(int i = 1;i <= n;i ++)
		cout << ne[i] << " ";
	return 0;
 } 

字符串

哈希

(题太多了,此处给的是哈希表)
#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ULL;
const int HA = 131,N = 1e6 + 10,Mod = 1e6 + 3;
char s[N];
ULL e[N],ne[N],idx;
int h[Mod];
ULL gethash(char s[]){
	ULL r = 0;
	for(int i = 1;s[i];i ++)
		r = r * HA + s[i];
	return r;
}
void insert(ULL x)
{
	int v = x % Mod;
	idx ++;
	e[idx] = x;
	ne[idx] = h[v];
	h[v] = idx;
}
bool query(ULL x)
{
	int v = x % Mod;
	for(int i = h[v];i;i = ne[i])
		if(e[i] == x)
			return true;
	return false;
}
int main()
{
	int n;
	cin >> n;
	int ans = 0;
	for(int i = 1;i <= n;i ++)
	{	
		cin >> s + 1;
		if(i == 1 || !query(gethash(s)))
		{
			ans ++;
			insert(gethash(s));
		}
	}
	cout << ans << endl;
	return 0;
}

Tire

这里是前缀的个数
#include<bits/stdc++.h>
using namespace std;
const int N = 3e6;
int tree[N][100],tot = 1,n,m,t,cnt[N];
char s[N];
template<typename T> void read(T &x)
{
	x = 0;int f = 1;char c;
	do{c = getchar();if(c == '-') f = -1;}while(!isdigit(c));
	do{x = x * 10 + c - '0';c = getchar();}while(isdigit(c));
	x *= f;
}
void insert(char s[])
{
	int len = strlen(s), p = 1;
	for(int k = 0;k < len;k ++)
	{
		int ch = s[k] - '0';
		if(!tree[p][ch]) tree[p][ch] = ++tot;
		p = tree[p][ch];
		cnt[p] ++;
	}
}
int query(char s[])
{
	int len = strlen(s),p = 1;
	for(int k = 0;k < len;k ++)
	{
		int ch = s[k] - '0';
		if(!tree[p][ch]) return 0;
		p = tree[p][ch];
	}
	return cnt[p];
}
int main()
{
	read(t);
	while(t --)
	{
		for(int i = 0;i <= tot;i ++)
			for(int j = 0;j <= 122;j ++)
				tree[i][j] = 0;
		for(int i = 0;i <= tot;i ++)
			cnt[i] = 0;
		tot = 1;
		read(n),read(m);
		for(int i = 1;i <= n;i ++)
		{
			scanf("%s",s);
			insert(s);
		}
		for(int i = 1;i <= m;i ++)
		{
			scanf("%s",s);
			cout << query(s) << endl;
		}
	}
	return 0;
}
这里是查找是否有这个字符串的问题
#include<bits/stdc++.h>
using namespace std;
const int N = 3e6;
int tree[N][100],tot = 1,n,m,t;
char s[N];
bool en[N];
template<typename T> void read(T &x)
{
	x = 0;int f = 1;char c;
	do{c = getchar();if(c == '-') f = -1;}while(!isdigit(c));
	do{x = x * 10 + c - '0';c = getchar();}while(isdigit(c));
	x *= f;
}
void insert(char s[])
{
	int len = strlen(s), p = 1;
	for(int k = 0;k < len;k ++)
	{
		int ch = s[k] - '0';
		if(!tree[p][ch]) tree[p][ch] = ++tot;
		p = tree[p][ch];
	}
	en[p] = 1;
}
bool query(char s[])
{
	int len = strlen(s),p = 1;
	for(int k = 0;k < len;k ++)
	{
		int ch = s[k] - '0';
		if(!tree[p][ch]) return 0;
		p = tree[p][ch];
	}
	return en[p];
}
int main()
{
	read(t);
	while(t --)
	{
		for(int i = 0;i <= tot;i ++)
			for(int j = 0;j <= 122;j ++)
				tree[i][j] = 0;
		for(int i = 0;i <= tot;i ++)
			en[i] = 0;
		tot = 1;
		read(n),read(m);
		for(int i = 1;i <= n;i ++)
		{
			scanf("%s",s);
			insert(s);
		}
		for(int i = 1;i <= m;i ++)
		{
			scanf("%s",s);
			cout << query(s) << endl;
		}
	}
	return 0;
}

其他

单调队列

#include<bits/stdc++.h>
using namespace std;
template<typename T> void rd(T &x)
{
	x = 0;int f = 1;char c;
	do{c = getchar();if(c == '-') f = -1;}while(!isdigit(c));
	do{x = x * 10 + c - '0';c = getchar();}while(isdigit(c));
	x *= f;
}
const int N = 1e6 + 66;
int n,k,a[N],p[N],q[N],tail,head = 1;
void maxx()
{
	head = 1;tail = 0;
	for(int i = 1;i <= n;i ++)
	{
		while(tail >= head && a[i] >= q[tail]) tail --;
		q[++ tail] = a[i];
		p[tail] = i;
		while(i - p[head] >= k) head ++;
		if(i >= k) cout << q[head] << " ";
	}
}
void minn()
{
	head = 1;tail = 0;
	for(int i = 1;i <= n;i ++)
	{
		while(tail >= head && a[i] <= q[tail]) tail --;
		q[++ tail] = a[i];
		p[tail] = i;
		while(i - p[head] >= k) head ++;
		if(i >= k)	cout << q[head] << " ";
	}
}
int main()
{
	rd(n),rd(k);
	for(int i = 1;i <= n;i ++)
		rd(a[i]);
	minn();
	putchar('\n');
	maxx();
	return 0;
}

单调栈

#include<bits/stdc++.h>
using namespace std;
template<typename T> void rd(T &x)
{
	x = 0;int f = 1;char c;
	do{c = getchar();if(c == '-') f = -1;}while(!isdigit(c));
	do{x = x * 10 + c - '0';c = getchar();}while(isdigit(c));
	x *= f;
}
const int N = 3e6 + 66;
int a[N],n,p[N];
stack<int> s;

int main()
{
	rd(n);
	for(int i = 1;i <= n;i ++)
		rd(a[i]);
	s.push(0);
	for(int i = n;i >= 1;i --)
	{
		while(a[i] >= a[s.top()] && s.size() > 1) 
			s.pop();
		p[i] = s.top();
		s.push(i);
	}
	for(int i = 1;i <= n;i ++)
		cout << p[i] << " ";
	return 0;
}

倍增

ST表

#include<bits/stdc++.h>
using namespace std;
template<typename T> inline void rd(T &x)
{
	x = 0;char c;long long f = 1;
	do{c = getchar();if(c == '-') f = -1;}while(!isdigit(c));
	do{x = x * 10 + c - '0';c = getchar();}while(isdigit(c));
	x *= f;
}
const long long N = 1e5 + 66;
long long f[N][20],o1[N],n,m,a[N];
inline void st_open()
{
	for(long long i = 1;i <= n;i ++) f[i][0] = a[i];
	for(long long j = 1;j <= o1[n];j ++)
		for(long long i = 1;i <= n - (1 << j) + 1;i ++)
			f[i][j] = max(f[i][j - 1],f[i + (1 << (j - 1))][j - 1]);
}
inline long long st_query(long long l,long long r)
{
	long long k = o1[r - l + 1];
	return max(f[l][k],f[r - (1 << k) + 1][k]);
}
signed main()
{
	rd(n),rd(m);
	for(long long i = 1;i <= n;i ++)
		o1[i] = log2(i),rd(a[i]);
	st_open();
	for(long long i = 1;i <= m;i ++)
	{
		long long l,r;rd(l),rd(r);
		printf("%lld\n",st_query(l,r));
	}
	return 0;	
}

树形结构

树状数组

模板1

#include<bits/stdc++.h>
using namespace std;
template<typename T> void rd(T&x)
{
	char c;int sign = 1;x = 0;
	// 判断是否是负数,以及去掉前面多余的字符
	do { c = getchar(); if(c == '-') sign = -1; }while(!isdigit(c)); 
	do { x = x * 10 + c - '0'; c = getchar(); }while(isdigit(c));
	x *= sign;
}
const int N = 5e5 + 66;
long long a[N],n,m;
int lowbit(int x){return x & -x;}
void add(int o,int v)
{
	for(int i = o;i <= n;i = i + lowbit(i))
		a[i] += v;
}
long long query(int x)
{
	long long res = 0;
	for(int i = x;i >= 1;i = i - lowbit(i))
		res += a[i];
	return res;
}
int main()
{
	rd(n),rd(m);
	for(int i = 1;i <= n;i ++)
	{
		int x;
		rd(x);
		add(i,x);
	}
	for(int i = 1;i <= m;i ++)
	{
		int od,x,y;
		rd(od),rd(x),rd(y);
		if(od == 1) add(x,y);
		else cout << (query(y) - query(x - 1)) << endl;
	}
	return 0;	
}

线段树

#include<bits/stdc++.h>
using namespace std;
template<typename T> void rd(T &x)
{
	x = 0;long long f = 1;char c;
	do{c = getchar();if(c == '-') f = -1;}while(!isdigit(c));
	do{x = x * 10 + c - '0';c = getchar();}while(isdigit(c));
	x *= f;
}
const long long N = 1e5 + 66;
long long n,m,a,b,c,ww,o[N];
struct node{
	long long l,r,add;
	long long sum;
}tree[N << 2];
void pushup(long long k){tree[k].sum = tree[k * 2].sum + tree[k * 2 + 1].sum;}//节点上放
void build(long long k,long long l,long long r)//建树
{
	if(l == r) {tree[k] = {l,r,0,o[l]};return ;}//叶子节点
	long long mid = l + r >> 1;
	build(k * 2,l,mid);
	build(k * 2 + 1,mid + 1,r);//左右子树
	tree[k].l = l,tree[k].r = r;
	pushup(k);
}
void change(long long x,long long k,long long v)//单点修改
{
	if(tree[k].l == x && tree[k].r == x){tree[k].sum += v;return ;}
	long long mid = tree[k].l + tree[k].r >> 1;
	if(x <= mid) change(x,k * 2,v);
	else change(x,k * 2 + 1,v);
	tree[k].sum = tree[k * 2].sum + tree[k * 2 + 1].sum;
}
void nowchange(long long k,long long v)//修改某个节点
{
	tree[k].sum += 1ll * v * (tree[k].r - tree[k].l + 1);
	tree[k].add += v;
}
void pushdown(long long k)//延迟下放
{
	//如果延迟
	if(tree[k].add != 0)
	{
		nowchange(k * 2,tree[k].add);
		nowchange(k * 2 + 1,tree[k].add);
		tree[k].add = 0;
	}
}
void INchange(long long x,long long y,long long k,long long v)//区间修改
{
	if(x <= tree[k].l && tree[k].r <= y){nowchange(k,v);return ;}
	pushdown(k);
	long long mid = tree[k].l + tree[k].r >> 1;
	if(x <= mid) INchange(x,y,k * 2,v);
	if(y >= mid + 1) INchange(x,y,k * 2 + 1,v);
	pushup(k);
}
long long query(long long x,long long y,long long k)//区间查询
{
	if(x <= tree[k].l && tree[k].r <= y) return tree[k].sum;
	pushdown(k);
	long long mid = tree[k].l + tree[k].r >> 1;
	long long res = 0;
	if(x <= mid) res += query(x,y,k * 2);
	if(y >= mid + 1) res += query(x,y,k * 2 + 1);
	return res;
}
int main()
{
	rd(n),rd(m);
	for(long long i = 1;i <= n;i ++) rd(o[i]);
	build(1,1,n);//建树
	while(m --)
	{
		rd(ww),rd(a),rd(b);
		if(ww == 1) rd(c),INchange(a,b,1,c);
		else printf("%lld\n",query(a,b,1)); 
	}
}
posted on 2025-08-11 18:40  medal_dreams  阅读(43)  评论(2)    收藏  举报