快读
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));
}
}