图论
目录
- P3367 【模板】并查集:
- 带权并查集 P1196 [NOI2002] 银河英雄传说
- (开O2 0分,不开ac(大雾))
- 种类并查集 P2024 [NOI2001] 食物链(这个做法似乎还是权值并查集,复习的时候最好这题和上一题都重新做)
- P3366 【模板】最小生成树:
- P3379 【模板】最近公共祖先(LCA)
- P3384 【模板】轻重链剖分/树链剖分(树剖+线段树+dfs+lca:
- P5903 【模板】树上 k 级祖先(长链剖分模板,但是其实重链剖分也可以做,不过慢一点)
- 树的直径 poj2631
(poj是我用过最难用的oj,没有之一)(dfs法) - 树的直径 U81904 【模板】树的直径 树形dp
- 圆方树 P4630 [APIO2018] 铁人两项
- P4779 【模板】单源最短路径(标准版)(迪杰斯特拉):
- P1807 最长路 单源最长路
- 分层图 P4568 [JLOI2011] 飞行路线
- P3371 【模板】单源最短路径(弱化版)(40)bellman_ford
- P3371 【模板】单源最短路径(弱化版)(spfa):
- spfa判负环 P3385 【模板】负环
- P6175 无向图的最小环问题 (floyd)
- P3371 【模板】单源最短路径(弱化版)(spfa
酸辣粉SLF优化): - 单源次短路
- loj 119. 单源最短路(Floyd)(80):
- P4017 最大食物链计数(拓扑):
- P3386 【模板】二分图最大匹配(匈牙利算法)
- P5960 【模板】差分约束算法
- P4782 【模板】2-SAT 问题
- P7771 【模板】欧拉路径
- 全局最小割 P5632 【模板】Stoer-Wagner算法
- P6086 【模板】Prufer 序列
- 点分治 P3806 【模板】点分治1
P3367 【模板】并查集:
#include<bits/stdc++.h>
#define for1(i,a,b) for(int i = a;i <= b;i++)
using namespace std;
int m,n,a[500000];
int zhao(int x)
{
if(x == a[x]) return x;
return a[x] = zhao(a[x]);
}
int main()
{
int x,y,z;
cin>>n>>m;
for1(i,1,n) a[i] = i;
for1(i,1,m)
{scanf("%d %d %d",&x,&y,&z);
if(x == 1) a[zhao(y)] = zhao(z);
else
{
if(zhao(y) == zhao(z)) cout<<'Y'<<endl;
else cout<<"N"<<endl;
}
}
return 0;
}
带权并查集 P1196 [NOI2002] 银河英雄传说
(开O2 0分,不开ac(大雾))
#include <iostream>
#include <cstdio>
#include<bits/stdc++.h>
#define for1(i,a,b) for(int i = a;i<=b;i++)
#define ll long long
#define mp(a,b) make_pair(a,b)
using namespace std;
int fa[500005],w[500005],t,num[500005];
int zhao(int x) {
if(x==fa[x])
return fa[x];
int k=fa[x];
fa[x]=zhao(fa[x]);
w[x]+=w[k];
num[x]=num[fa[x]];
return fa[x];
}
int main() {
cin>>t;
for1(i,1,500005)
fa[i]=i,num[i]=1;
for1(i,1,t)
{
char c;
int a,b;
cin>>c>>a>>b;
if(c=='M') {
int ji1=zhao(a),r2=zhao(b);
if(ji1==r2)
continue;
else
{
fa[ji1]=r2;
w[ji1]=w[r2]+num[r2];
num[r2]+=num[ji1];
num[ji1]=num[r2];
}
}
else {
int ji1=zhao(a),r2=zhao(b);
if(ji1!=r2)
printf("-1\n");
else
printf("%d\n",abs(w[a]-w[b])-1);
}
}
return 0;
}
种类并查集 P2024 [NOI2001] 食物链(这个做法似乎还是权值并查集,复习的时候最好这题和上一题都重新做)
#include<bits/stdc++.h>
#define s_it set<node>::iterator //s_it = set_iterator
#define for1(i,a,b) for(int i=a;i<=b;i++)
#define mp(a,b) make_pair(a,b)
#define ll long long
using namespace std;
int fa[3000005];//0同族 1猎物 2天敌
int n,k,ans;
inline int read()
{
int sum=0;
char ch=getchar();
while(ch>'9'||ch<'0') ch=getchar();
while(ch>='0'&&ch<='9') sum=sum*10+ch-48,ch=getchar();
return sum;
}
int find(int x)
{
if(x==fa[x]) return x;
return fa[x]=find(fa[x]);
}
int he(int x,int y)
{
int r1=find(fa[x]),r2=find(fa[y]);
fa[r1]=r2;
return 0;
}
int main()
{
int x,y,z;
n=read(),k=read();
for1(i,1,n*3) fa[i]=i;
for1(i,1,k)
{
z=read(),x=read(),y=read();
if(x>n||y>n)//?逆天数据
{
ans++;
continue;
}
if(z==1)
{
if(find(x+n)==find(y)||find(x+2*n)==find(y))//倘若y已经是x的天敌或猎物了
ans++;
else
{
he(x,y);//同族
he(x+n,y+n);//同猎物
he(x+2*n,y+2*n);//同天敌
}
}
else if(z==2)
{
if(x==y) //?逆天数据
{
ans++;
continue;
}
if(find(x)==find(y)||find(x+2*n)==find(y))//倘若x是y的同族 或者天敌
ans++;
else
{
he(x,y+2*n);//x是y的天敌
he(x+n,y);//x的猎物就是y
he(x+2*n,y+n);//x的天敌就是y的猎物
}
}
}
printf("%d\n",ans);
return 0;
}
P3366 【模板】最小生成树:
#include<bits/stdc++.h>
#define for1(i,a,b) for(int i = a;i<=b;i++)
using namespace std;
struct node{
int from;
int to;
int w;
int nex;
}a[500005];
int n,m,fa[500005],ans;
bool cmp(node x,node y)
{
return x.w<y.w;
}
int gf(int x)
{
if(fa[x]==x) return x;
return fa[x]=gf(fa[x]);
}
int main()
{
scanf("%d%d",&n,&m);
for1(i,1,n) fa[i]=i;
for1(i,1,m)
scanf("%d%d%d",&a[i].from,&a[i].to,&a[i].w);
sort(a+1,a+m+1,cmp);
for1(i,1,m)
{
int x=gf(a[i].from),y=gf(a[i].to);
if(x!=y)
{
ans+=a[i].w;
fa[x]=y;
}
}
int ji=gf(fa[1]);
for1(i,1,n)
{
if(gf(fa[i])!=ji)
{
printf("orz\n");
return 0;
}
}
cout<<ans;
return 0;
}
P3379 【模板】最近公共祖先(LCA)
#include <bits/stdc++.h>
#define for1(i,a,b) for(int i = a;i <= b; i++)
#define mp(a,b) make_pair(a,b)
using namespace std;
struct node{
int from;
int to;
int nex;
int w;
}a[500005*4];
int hd[500005],cnt;
int n,m,d[500005],s,fa[500005][30];
void ru(int x,int y)
{
a[++cnt].from=x;
a[cnt].to=y;
a[cnt].nex=hd[x];
hd[x]=cnt;
}
void dfs(int x,int f)
{
d[x]=d[f]+1;
fa[x][0]=f;
for(int i=1;(1<<i)<=d[x];i++)
fa[x][i]=fa[fa[x][i-1]][i-1];
for(int i=hd[x];i;i=a[i].nex)
{
if(a[i].to!=f)
dfs(a[i].to,x);
}
}
int lca(int x,int y)
{
if(d[x]>d[y]) swap(x,y);
for(int i = 21;i>=0;i--)
if(d[y]-(1<<i)>=d[x])
y=fa[y][i];
if(x==y) return x;
for(int i = 21;i>=0;i--)
{
if(fa[x][i]==fa[y][i]) continue;
x=fa[x][i];
y=fa[y][i];
}
return fa[x][0];
}
int main() {
int x,y;
cin>>n>>m>>s;
for1(i,1,n-1)
{
scanf("%d%d",&x,&y);
ru(x,y);
ru(y,x);
}
dfs(s,0);
for1(i,1,m)
{
scanf("%d%d",&x,&y);
printf("%d\n",lca(x,y));
}
return 0;
}
P3384 【模板】轻重链剖分/树链剖分(树剖+线段树+dfs+lca:
https://www.cnblogs.com/chinhhh/p/7965433.html
#include<bits/stdc++.h>
using namespace std;
#define for1(i,a,b) for(int i = a;i<=b;i++)
#define ll long long
struct node{
int l,r,lan,zhi;
}s[500005*5];//线段树数组、lazy操作
const int maxn=200000+10;
int n,m,r,mod;
//见题意
struct no
{
int to;
int nex;
}a[maxn];
int cnt,hd[maxn],w[maxn],wt[maxn];
//链式前向星数组,w[]、wt[]初始点权数组
int son[maxn],id[maxn],fa[maxn],ji,d[maxn],siz[maxn],top[maxn];
//son[]重儿子编号,id[]新编号,fa[]父亲节点,ji dfs序,d[]深度,siz[]子树大小,top[]当前链顶端节点
int res=0;
//查询答案
void ru(int x,int y){
a[++cnt].to=y;
a[cnt].nex=hd[x];
hd[x]=cnt;
}
void build(int q,int l,int r)
{
s[q].lan=0;
s[q].l=l;s[q].r=r;
if(l==r)
{
s[q].zhi=wt[l];
if(s[q].zhi>mod) s[q].zhi%=mod;
return ;
}
int mid = (l+r)/2;
build(q*2,l,mid);
build(q*2+1,mid+1,r);
s[q].zhi=(s[q*2].zhi+s[q*2+1].zhi)%mod;
return ;
}
void chuan(int q)
{
if(s[q].lan!=0)
{
s[q*2].zhi=(s[q*2].zhi+s[q].lan*(s[q*2].r-s[q*2].l+1))%mod;
s[q*2+1].zhi=(s[q*2+1].zhi+s[q].lan*(s[q*2+1].r-s[q*2+1].l+1))%mod;
s[q*2].lan+=s[q].lan;
s[q*2+1].lan+=s[q].lan;
s[q].lan=0;
}
}
void xg(int q,int l,int r,int k)
{
int mid = (s[q].r+s[q].l)/2;
if(s[q].r<=r&&s[q].l>=l)
{
s[q].zhi=(s[q].zhi+k*(s[q].r-s[q].l+1))%mod;
s[q].lan+=k;
return ;
}
chuan(q);
if(l<=mid) xg(q*2,l,r,k);
if(r>mid) xg(q*2+1,l,r,k);
s[q].zhi=(s[q*2].zhi+s[q*2+1].zhi)%mod;
}
int cx(int q,int l,int r)
{
int mid = (s[q].r+s[q].l)/2;
if(s[q].r<=r&&s[q].l>=l)
{
return s[q].zhi%=mod;
}
chuan(q);
int ans = 0;
if(l<=mid) ans=(ans+cx(q*2,l,r))%mod;;
if(r>mid) ans=(ans+cx(q*2+1,l,r))%mod;;
return ans%mod;
}
void dfs1(int x,int f,int deep)//处理 深度dep[] 点的父亲fa[] 节点的子树大小 重儿子编号son[]
{
d[x]=deep;
fa[x]=f;
siz[x]=1;
int zhong=-1;//记录重儿子
for(int i=hd[x];i;i=a[i].nex)
{
int v=a[i].to;
if(v==f) continue;
dfs1(v,x,deep+1);
siz[x]+=siz[v];
if(siz[v]>zhong) zhong=siz[v],son[x]=v;//找重儿子
}
return ;
}
void dfs2(int x,int topf)//剖数成莲,给节点赋予新编号
{
id[x]=++ji;//节点的新编号
wt[ji]=w[x];
top[x]=topf;//链顶
if(!son[x]) return; //sonx[x]为x的 重儿子,如果一个节点没有重儿子,代表他没有儿子
dfs2(son[x],topf);//优先搜重儿子
for(int i=hd[x];i;i=a[i].nex)
{
int v=a[i].to;
if(v!=son[x]&&v!=fa[x]) dfs2(v,v);//其他轻儿子变成新链的链顶
}
}
int cx_lujing(int x,int y)//查询x-y的路径权值和
{
int ans=0;
while(top[x]!=top[y]) //两个点不在一条链上的时候(其实相当于在找lca)
{
if(d[top[x]]<d[top[y]]) swap(x,y);//让x成为链顶深度更深的点
ans+=cx(1,id[top[x]],id[x]);//加上从链顶到x的权值和
ans%=mod;
x=fa[top[x]];//向上跳
}
//两个点在一条链上 (此时x或y中的一个就是x和y的lca)
if(d[x]>d[y]) swap(x,y);//深度更浅的是lca
ans+= cx(1,id[x],id[y]);//不在一条链上是相当于在求x到lca(x,y) 的权值和,此时相当于再求lca(x,y)到y的权值和
return ans%mod;
}
int cx_zishu(int x)//查询x及其子树的权值和
{
return cx(1,id[x],id[x]+siz[x]-1);//子树区间右端点为id[x]+siz[x]-1
}
void xg_lujing(int x,int y,int k)//修改x-y的路径权值和
{
k%=mod;
while(top[x]!=top[y]) //两个点不在一条链上的时候(其实相当于在找lca)
{
if(d[top[x]]<d[top[y]]) swap(x,y);//让x成为链顶深度更深的点
xg(1,id[top[x]],id[x],k);//修改从链顶到x的权值和
x=fa[top[x]];//向上跳
}
//两个点在一条链上 (此时x或y中的一个就是x和y的lca)
if(d[x]>d[y]) swap(x,y);//深度更浅的是lca
xg(1,id[x],id[y],k);//不在一条链上是相当于在修改x到lca(x,y) 的权值和,此时相当于再修改lca(x,y)到y的权值和
return ;
}
void xg_zishu(int x,int k)//修改x及其子树的权值和
{
xg(1,id[x],id[x]+siz[x]-1,k);//子树区间右端点为id[x]+siz[x]-1
return ;
}
int main(){
int a,b;
cin>>n>>m>>r>>mod;
for1(i,1,n) scanf("%d",w+i);
for1(i,1,n-1)
{
scanf("%d%d",&a,&b);
ru(a,b);
ru(b,a);
}
dfs1(r,0,1);
dfs2(r,r);
build(1,1,n);
while(m--)
{
int k,x,y,z;
scanf("%d",&k);
if(k==1){
scanf("%d%d%d",&x,&y,&z);
xg_lujing(x,y,z);
}
else if(k==2){
scanf("%d%d",&x,&y);
printf("%d\n",cx_lujing(x,y));
}
else if(k==3){
scanf("%d%d",&x,&y);
xg_zishu(x,y);
}
else{
scanf("%d",&x);
printf("%d\n",cx_zishu(x));
}
}
}
新版(懒得补注释,但是新版码风更好
#include<bits/stdc++.h>
#define ls q << 1
#define rs q << 1 | 1
#define ll long long
#define for1(i,a,b) for(int i = a;i <= b;i++)
using namespace std;
const int maxn = 2e6 + 5;
struct node{
int nex;
int to;
}a[maxn];
int hd[maxn],cnt;
int n,m,r,mod;
int son[maxn],fa[maxn],siz[maxn],d[maxn],top[maxn],id[maxn];
int w[maxn],wt[maxn];
int ji;
struct Point{
int val;
int lan;
};
struct Tree{
Point s[maxn<<2];
void Build(int q, int l, int r)
{
if(l == r)
{
s[q].val = wt[l];
return ;
}
int mid = (l + r) >> 1;
Build(ls,l,mid);
Build(rs,mid + 1,r);
s[q].val = (s[ls].val + s[rs].val) % mod;
return ;
}
void chuan(int q,int l, int r)
{
int mid = (l + r) >> 1;
if(s[q].lan == 0) return ;
s[ls].val += (mid - l + 1) * s[q].lan;
s[rs].val += (r - mid - 1 + 1) * s[q].lan;
s[ls].lan += s[q].lan;
s[rs].lan += s[q].lan;
s[q].lan = 0;
return ;
}
void Change(int q, int l, int r, int L, int R, int k)
{
if(L <= l && r <= R)
{
s[q].val += (r - l + 1) * k;
s[q].lan += k;
return ;
}
chuan(q,l,r);
int mid = (l + r) >> 1;
if(L <= mid) Change(ls,l,mid,L,R,k);
if(R > mid) Change(rs,mid + 1,r,L,R,k);
s[q].val = (s[ls].val + s[rs].val) % mod;
}
int Query(int q, int l, int r, int L, int R)
{
if(L <= l && r <= R)
{
return s[q].val;
}
chuan(q,l,r);
int mid = (l + r) >> 1;
int res = 0;
if(L <= mid) res += Query(ls,l,mid,L,R),res %= mod;
if(R > mid) res += Query(rs,mid + 1,r,L,R),res %= mod;
return res%mod;
}
}Tree;
void ru(int x, int y)
{
a[++cnt].to = y;
a[cnt].nex = hd[x];
hd[x] = cnt;
}
void dfs1(int x, int f, int deep)
{
d[x] = deep;
fa[x] = f;
siz[x] = 1;
int zhong = -1;
for(int i = hd[x];i;i = a[i].nex)
{
int v = a[i].to;
if(v == f) continue;
dfs1(v,x,deep + 1);
siz[x] += siz[v];
if(siz[v] > zhong) zhong = siz[v],son[x] = v;
}
}
void dfs2(int x, int topf)
{
id[x] = ++ ji;
wt[ji] = w[x];
top[x] = topf;
if(!son[x]) return ;
dfs2(son[x],topf);
for(int i = hd[x];i;i = a[i].nex)
{
int v = a[i].to;
if(v != son[x] && v != fa[x])
dfs2(v,v);
}
return ;
}
int Query_LuJing(int x, int y)
{
int ans = 0;
while(top[x] != top[y])
{
if(d[top[x]] < d[top[y]])
swap(x,y);
ans += Tree.Query(1,1,n,id[top[x]],id[x]);
ans %= mod;
x = fa[top[x]];
}
if(d[x] > d[y]) swap(x,y);
ans += Tree.Query(1,1,n,id[x],id[y]);
return ans%mod;
}
void Change_LuJing(int x, int y, int k)
{
k %= mod;
int ans = 0;
while(top[x] != top[y])
{
if(d[top[x]] < d[top[y]])
swap(x,y);
Tree.Change(1,1,n,id[top[x]],id[x],k);
x = fa[top[x]];
}
if(d[x] > d[y]) swap(x,y);
Tree.Change(1,1,n,id[x],id[y],k);
return ;
}
void Change_ZiShu(int x, int k)
{
Tree.Change(1,1,n,id[x],id[x] + siz[x] - 1,k);
return ;
}
int Query_ZiShu(int x)
{
return Tree.Query(1,1,n,id[x],id[x] + siz[x] - 1);
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> n >> m >> r >> mod;
int x,y,z,k;
for1(i,1,n) cin >> w[i];
for1(i,1,n - 1)
{
cin >> x >> y;
ru(x,y);
ru(y,x);
}
dfs1(r,0,1);
dfs2(r,r);
Tree.Build(1,1,n);
for1(i,1,m)
{
cin >> k;
if(k == 1)
{
cin >> x >> y >> z;
Change_LuJing(x,y,z);
}
else if(k == 2)
{
cin >> x >> y;
cout << Query_LuJing(x,y)% mod << '\n';
}
else if(k == 3)
{
cin >> x >> y;
Change_ZiShu(x,y);
}
else
{
cin >> x;
cout << Query_ZiShu(x)% mod << '\n';
}
}
return 0;
}
P5903 【模板】树上 k 级祖先(长链剖分模板,但是其实重链剖分也可以做,不过慢一点)
#include<bits/stdc++.h>
#define ll long long
#define for1(i,a,b) for(register ll i = a;i <= b;i ++)
using namespace std;
const ll maxn = 5e5 + 5;
struct node{
ll nex;
ll to;
}a[maxn];
ll hd[maxn],cnt;
void ru(ll x, ll y)
{
a[++cnt].to = y;
a[cnt].nex = hd[x];
hd[x] = cnt;
}
ll n,m;
ll coun;
ll top[maxn];
ll fa[maxn][21],w[maxn],h[maxn];
ll lg[maxn],dep[maxn],id[maxn];
ll U[maxn],D[maxn];
void dfs1(ll x)
{
for1(i,1,19)
fa[x][i] = fa[fa[x][i - 1]][i - 1];
for(ll i = hd[x];i;i = a[i].nex)
{
ll v= a[i].to;
dep[v] = h[v] = dep[x] + 1;
dfs1(v);
h[x] = max(h[x],h[v]);
if(h[v] > h[w[x]]) w[x] = v;
}
}
void dfs2(ll x, ll tp)
{
id[x] = ++ coun;
D[coun] = x;
U[coun] = tp;
if(w[x])
{
top[w[x]] = top[x];
dfs2(w[x],fa[tp][0]);
}
for(ll i = hd[x];i;i = a[i].nex)
{
ll v= a[i].to;
if(v == w[x]) continue;
top[v] = v;
dfs2(v,v);
}
}
ll rt;
unsigned int S;
unsigned int cl()
{
S ^= S << 13;
S ^= S >> 17;
S ^= S << 5;
return S;
}
ll query(ll x, ll k)
{
if(k == 0) return x;
x = fa[x][lg[k]];
k -= (1 << lg[k]);
k -= dep[x] - dep[top[x]];//跳到链顶
x = top[x];
if(k >= 0) return U[id[x] + k];//同一条链向下还是向上
return D[id[x] - k];
}
int main()
{
cin >> n >> m >> S;
lg[0] = -1;
for1(i,1,n)
lg[i] = lg[i >> 1] + 1;
rt = 1;
for1(i,1,n)
{
cin >> fa[i][0];
if(fa[i][0] == 0) rt = i;
else ru(fa[i][0],i);
}
dep[rt] = 1;
dfs1(rt);
top[rt] = rt;
dfs2(rt,rt);
ll ans = 0;
ll lans = 0;
for1(i,1,m)
{
ll x = ( cl() ^ lans ) % n + 1;
ll k = (cl() ^ lans) % dep[x];
lans = query(x,k);
ans ^= 1ll * i * lans;
}
cout << ans << '\n';
return 0;
}
树的直径 poj2631(poj是我用过最难用的oj,没有之一)(dfs法)
#include<iostream>
#include<stdio.h>
#define for1(i,a,b) for(int i = a;i<=b;i++)
#define ll long long
#define mp(a,b) make_pair(a,b)
using namespace std;
struct node{
int to;
int nex;
int w;
}a[500005];
int hd[500005],cnt;
int n,m;
int dep[500005];
int ans,ji;
int r1,r2;
void ru(int x,int y,int z)
{
a[++cnt].to=y;
a[cnt].w=z;
a[cnt].nex=hd[x];
hd[x]=cnt++;
}
void dfs(int x,int fa)
{
if(dep[x]>ans)
{
ans=dep[x];
ji=x;
}
for(int i=hd[x];i;i=a[i].nex)
{
int v=a[i].to;
if(v==fa) continue;
dep[v]=dep[x]+a[i].w;
dfs(v,x);
}
return ;
}
int main()
{
int x,y,z;
n=1;
while(scanf("%d%d%d",&x,&y,&z)!=EOF)
{
n++;
ru(x,y,z);
ru(y,x,z);
}
dfs(1,0);
r1=ji;
ji=0;
ans=0;
for1(i,1,n) dep[i]=0;
dfs(r1,0);
r2=ji;
cout<<ans<<endl;
return 0;
}
树的直径 U81904 【模板】树的直径 树形dp
#include<bits/stdc++.h>
#define for1(i,a,b) for(ll i = a;i<=b;i++)
#define ll long long
#define mp(a,b) make_pair(a,b)
using namespace std;
struct node{
ll to;
ll nex;
ll w;
}a[2000005];
ll hd[500005],cnt;
ll n,m;
int d[500005],f[500005];
bool vis[500005];
ll ans,ji;
ll r1,r2;
void ru(ll x,ll y,ll z)
{
a[++cnt].to=y;
a[cnt].w=z;
a[cnt].nex=hd[x];
hd[x]=cnt++;
}
void dfs(int x,int fa)
{
if(x==0) return;
vis[x]=1;
for(int i=hd[x];i;i=a[i].nex)
{
int v=a[i].to;
int w=a[i].w;
if(v==fa) continue;
if(!vis[v])
{
dfs(v,x);
f[x]=max(max(f[x],d[x]),max(d[v]+w,d[x]+d[v]+w));
d[x]=max(max(d[x],w),d[v]+w);
}
}
}
int main()
{
ll x,y,z;
cin>>n;
for1(i,1,n-1)
{
scanf("%d%d%d",&x,&y,&z);
ru(x,y,z);
ru(y,x,z);
}
dfs(1,0);
int ans=INT_MIN;
for1(i,1,n) ans=max(ans,f[i]);
printf("%d\n",ans);
return 0;
}
圆方树 P4630 [APIO2018] 铁人两项
本质上就是边双加了几行代码
#include<bits/stdc++.h>
#define ll long long
#define for1(i,a,b) for(int i = a;i <= b;i ++)
using namespace std;
const int maxn = 2e6+5;
struct point{
int nex;
int to;
}a[maxn],b[maxn];
int hd[maxn],cnt;
int hd2[maxn],cnt2,n,m;
void ru(int x, int y)
{
a[++cnt].to = y;
a[cnt].nex = hd[x];
hd[x] = cnt;
}
void ru2(int x, int y)
{
b[++cnt2].to = y;
b[cnt2].nex = hd2[x];
hd2[x] = cnt2;
}
int dfn[maxn],low[maxn],t;
int zhan[maxn],top,w[maxn];
int vis[maxn],siz[maxn],num;
ll ji,ans;
void tarjan(int x)
{
dfn[x] = low[x] = ++t;
zhan[++top] = x;
++num;
for(int i = hd[x];i;i = a[i].nex)
{
int v = a[i].to;
if(!dfn[v])
{
tarjan(v);
low[x] = min(low[x],low[v]);
if(low[v] == dfn[x])
{
w[++ji] = 0 ;
for(int j = 0;j != v;top--)
{
j = zhan[top];
ru2(ji,j);
ru2(j,ji);
w[ji] ++ ;
}
ru2(ji,x);
ru2(x,ji);
w[ji] ++ ;
}
}
else low[x] = min(low[x],dfn[v]);
}
return ;
}
void dfs(int x, int fa)
{
vis[x] = 1;
if(x <= n)
siz[x] = 1;//圆点才算
else siz[x] = 0;
for(int i = hd2[x];i;i = b[i].nex)
{
int v = b[i].to;
if(v == fa) continue;
dfs(v,x);
ans += 2ll * w[x] * siz[x] * siz[v];
siz[x] += siz[v];
}
ans += 2ll * w[x] * siz[x] * (num - siz[x]);
}
int main()
{
cin >> n >> m;
ji = n;
for1(i,1,n) w[i] = -1;
int x,y;
for1(i,1,m)
{
cin >> x >> y;
ru(x,y);
ru(y,x);
}
for1(i,1,n)
if(!dfn[i])
{
num = 0;
tarjan(i),top--;
dfs(i,0);
}
cout << ans << endl;
// for1(x,1,ji)
// {
// for(int i = hd2[x];i;i = b[i].nex)
// {
// int v = b[i].to;
// cout << x << ' ' << v << endl;
// }
// }
return 0;
}
P4779 【模板】单源最短路径(标准版)(迪杰斯特拉):
#include <bits/stdc++.h>
#define for1(i,a,b) for(int i = a;i <= b; i++)
#define mp(a,b) make_pair(a,b)
using namespace std;
priority_queue<pair<int, int> >q;
struct node {
int next;
int to;
int w;
} a[500001];
int n, head[500001], cnt, m, s;
int vis[500001];
long long ans[500001];
void ru(int x, int y, int z) {
a[++cnt].to = y;
a[cnt].w = z;
a[cnt].next = head[x];
head[x] = cnt;
}
int main() {
int x, y, z;
scanf("%d%d%d", &n, &m, &s);
for1(i, 1, m) {
scanf("%d%d%d", &x, &y, &z);
ru(x, y, z);
}
for1(i, 1, n) ans[i] = 2147483647;
ans[s] = 0;
q.push(mp(0,s));
while (!q.empty()) {
int x = q.top().second;
q.pop();
if (vis[x] == 1)
continue;
vis[x] = 1;
for (int i = head[x]; i; i = a[i].next) {
if (ans[a[i].to] > ans[x] + a[i].w) {
ans[a[i].to] = ans[x] + a[i].w;
q.push(mp(-ans[a[i].to], a[i].to));
}
}
}
for1(i, 1, n) printf("%d ", ans[i]);
return 0;
}
P1807 最长路 单源最长路
用dij改的,输入时边权改成负的,并且去掉vis
#include <bits/stdc++.h>
#define for1(i,a,b) for(int i = a;i <= b; i++)
#define mp(a,b) make_pair(a,b)
using namespace std;
priority_queue<pair<int, int> >q;
struct node {
int next;
int to;
int w;
} a[5000001];
int n, head[5000001], cnt = 1, m, s;
long long ans[5000001];
void ru(int x, int y, int z) {
a[cnt].to = y;
a[cnt].w = z;
a[cnt].next = head[x];
head[x] = cnt++;
}
int main() {
int x, y, z;
scanf("%d%d", &n, &m);
s = 1;
for1(i, 1, m) {
scanf("%d%d%d", &x, &y, &z);
ru(x, y, -z);
}
for1(i, 1, n) ans[i] = 2147483647;
ans[s] = 0;
q.push(mp(0, s));
while (!q.empty()) {
int x = q.top().second;
q.pop();
for (int i = head[x]; i != 0; i = a[i].next) {
if (ans[a[i].to] > ans[x] + a[i].w) {
ans[a[i].to] = ans[x] + a[i].w;
q.push(mp(-ans[a[i].to], a[i].to));
}
}
}
if (ans[n] == 2147483647)
cout << -1;
else
cout << -ans[n];
return 0;
}
分层图 P4568 [JLOI2011] 飞行路线
#include <bits/stdc++.h>
#define for1(i,a,b) for(int i = a;i <= b; i++)
#define mp(a,b) make_pair(a,b)
#define ll long long
using namespace std;
priority_queue<pair<ll,ll> >q;
struct node {
int next;
int to;
ll w;
} a[5000001];
int n, head[1000001], cnt, m, s,t,k;
int vis[1000001];
ll ans[1000001];
void ru(int x, int y, int z) {
a[++cnt].to = y;
a[cnt].w = z;
a[cnt].next = head[x];
head[x] = cnt;
}
int main() {
int x, y, z;
scanf("%d%d%d", &n, &m, &k);
scanf("%d%d",&s,&t);
s++,t++;
for1(i, 1, m)
{
scanf("%d%d%d", &x, &y, &z);x++,y++;
ru(x, y, z);
ru(y, x, z);
for1(j,1,k)
{
ru(y+(j-1)*n,x+j*n,0),ru(x+(j-1)*n,y+j*n,0);
ru(y+j*n,x+j*n,z),ru(x+j*n,y+j*n,z);
}
}
memset(ans, 0x3f, sizeof(ans));
ans[s] = 0;
q.push(mp(0,s));
while (!q.empty()) {
int x = q.top().second;
q.pop();
if (vis[x] == 1)
continue;
vis[x] = 1;
for (int i = head[x]; i; i = a[i].next) {
if (ans[a[i].to] > ans[x] + a[i].w) {
ans[a[i].to] = ans[x] + a[i].w;
q.push(mp(-ans[a[i].to], a[i].to));
}
}
}
ll rans=1e15;
for1(i,0,k) rans=min(rans,ans[t+i*n]);
cout<<rans<<endl;
return 0;
}
P3371 【模板】单源最短路径(弱化版)(40)bellman_ford
#include<bits/stdc++.h>
#define for1(i,a,b) for(ll i = a;i <= b; i++)
#define mp(a,b) make_pair(a,b)
#define ll long long
using namespace std;
queue<int> q;
struct node {
ll nex;
ll to;
ll w;
} t[500005];
const ll inf = 2147483647;
ll n,m,s,hd[500005],cnt,ans[500005];
void ru(ll x,ll y,ll z) {
t[++cnt].to=y;
t[cnt].w=z;
t[cnt].nex=hd[x];
hd[x]=cnt;
}
int main() {
ll x,y,z;
scanf("%lld%lld%lld",&n,&m,&s);
for1(i,1,m) {
scanf("%lld%lld%lld",&x,&y,&z);
ru(x,y,z);
}
for1(i,1,n)ans[i]=inf;
ans[s]=0;
for(int k=1; k<n; k++) {
for(int x=1; x<=n; x++) {
for(ll i = hd[x]; i; i=t[i].nex) {
int v=t[i].to;
if(ans[v]>ans[x]+t[i].w) {
ans[v]=ans[x]+t[i].w;
}
}
}
}
for1(i,1,n) printf("%lld ",ans[i]);
return 0;
}
P3371 【模板】单源最短路径(弱化版)(spfa):
#include<bits/stdc++.h>
#define for1(i,a,b) for(ll i = a;i <= b; i++)
#define mp(a,b) make_pair(a,b)
#define ll long long
using namespace std;
queue<int> q;
struct node{
ll nex;
ll to;
ll w;
}t[500005];
const ll inf = 2147483647;
ll n,m,s,hd[500005],cnt,ans[500005],vis[500005];//spfa 入队的vis=1 没入=0
void ru(ll x,ll y,ll z)
{
t[++cnt].to=y;
t[cnt].w=z;
t[cnt].nex=hd[x];
hd[x]=cnt;
}
int main()
{
ll x,y,z;
scanf("%lld%lld%lld",&n,&m,&s);
for1(i,1,m)
{
scanf("%lld%lld%lld",&x,&y,&z);
ru(x,y,z);
}
for1(i,1,n)ans[i]=inf;
ans[s]=0;
q.push(s);vis[s]=1;
while(!q.empty())
{
x=q.front();
q.pop();
vis[x]=0;
for(ll i = hd[x];i;i=t[i].nex)
{
int v=t[i].to;
if(ans[v]>ans[x]+t[i].w)
{
ans[v]=ans[x]+t[i].w;
if(vis[v]==0)
{
vis[v]=1;
q.push(v);
}
}
}
}
for1(i,1,n) printf("%lld ",ans[i]);
return 0;
}
spfa判负环 P3385 【模板】负环
#include<bits/stdc++.h>
#define for1(i,a,b) for(int i = a;i<=b;i++)
#define ll long long
#define mp(a,b) make_pair(a,b)
using namespace std;
int n,m;
struct node {
int to,w,nex;
} a[500005];
int hd[5005],cnt;
void chushihua() {
for1(i,0,500005) a[i].nex=0;
for1(i,0,5005) hd[i]=0;
cnt=0;
}
void ru(int u,int v,int w) {
a[++cnt].to=v;
a[cnt].w=w;
a[cnt].nex=hd[u];
hd[u]=cnt;
}
queue<int> dl;
int ans[5005],vis[5005],ji[5005];
bool spfa() {
memset(ans,0x3f,sizeof(ans));
memset(vis,0,sizeof(vis));
memset(ji,0,sizeof(ji));
ans[1]=0;
vis[1]=true;
dl.push(1);
while(!dl.empty()) {
int x=dl.front();
dl.pop();
vis[x]=false;
for(int i=hd[x]; i; i=a[i].nex) {
int y=a[i].to,z=a[i].w;
if(ans[y]>ans[x]+z) {
ans[y]=ans[x]+z;
ji[y]=ji[x]+1;
if(ji[y]>n) return true;
if(!vis[y]) {
dl.push(y);
vis[y]=true;
}
}
}
}
return false;
}
int main() {
int T;
scanf("%d",&T);
while(T--) {
chushihua();
scanf("%d%d",&n,&m);
for1(i,1,m) {
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
ru(u,v,w);
if(w>=0) ru(v,u,w);
}
if(spfa())printf("YES\n");
else printf("NO\n");
}
return 0;
}
P6175 无向图的最小环问题 (floyd)
#include<bits/stdc++.h>
#define for1(i,a,b) for(int i = a;i<=b;i++)
#define ll long long
#define mp(a,b) make_pair(a,b)
using namespace std;
ll a[505][505],dis[505][505];
ll n,m;
const ll inf=1e9;
ll ans=inf;
int main()
{
ll x,y,w;
cin>>n>>m;
for1(i,1,n)
for1(j,1,n)
dis[i][j]=a[i][j]=(i==j)?0:inf;
for1(i,1,m)
{
scanf("%lld %lld %lld",&x,&y,&w);
a[x][y]=min(a[x][y],w);
a[y][x]=min(a[y][x],w);
dis[x][y]=a[x][y];
dis[y][x]=a[y][x];
}
for1(k,1,n)
{
for1(i,1,k-1)
for1(j,i+1,k-1)
{
ans=min(ans,dis[i][j]+a[j][k]+a[k][i]);
}
for1(i,1,n)
for1(j,1,n)
dis[i][j] = min(dis[i][j],dis[i][k]+dis[k][j]),
dis[j][i] = dis[i][j];
}
if(ans==inf)
printf("No solution.\n");
else cout<<ans<<endl;
return 0;
}
P3371 【模板】单源最短路径(弱化版)(spfa 酸辣粉 SLF优化):
#include<bits/stdc++.h>
#define for1(i,a,b) for(ll i = a;i <= b; i++)
#define mp(a,b) make_pair(a,b)
#define ll long long
using namespace std;
deque<int> q;
struct node{
ll nex;
ll to;
ll w;
}t[500005];
const ll inf = 2147483647;
ll n,m,s,hd[500005],cnt,ans[500005],vis[500005];//spfa 入队的vis=1 没入=0
void ru(ll x,ll y,ll z)
{
t[++cnt].to=y;
t[cnt].w=z;
t[cnt].nex=hd[x];
hd[x]=cnt;
}
int main()
{
ll x,y,z;
scanf("%lld%lld%lld",&n,&m,&s);
for1(i,1,m)
{
scanf("%lld%lld%lld",&x,&y,&z);
ru(x,y,z);
}
for1(i,1,n)ans[i]=inf;
ans[s]=0;
q.push_back(s);vis[s]=1;
while(!q.empty())
{
x=q.front();
q.pop_front();
vis[x]=0;
for(ll i = hd[x];i;i=t[i].nex)
{
int v=t[i].to;
if(ans[v]>ans[x]+t[i].w)
{
ans[v]=ans[x]+t[i].w;
if(vis[v]==0)
{
vis[v]=1;
if(q.empty()||ans[v]>ans[q.front()]) q.push_back(v);
else q.push_front(v);
}
}
}
}
for1(i,1,n) printf("%lld ",ans[i]);
return 0;
}
单源次短路
先记录下最短路径,然后每次删掉一条路径(说是删掉,实际操作时特判就得了),然后求最短路,得到的所有删过边的最短路的最小值就是单源次短路
找不到例题所以不知道代码对不对,而且不能有重边(特判的时候会把所有重边都删掉)
#include <bits/stdc++.h>
#define for1(i,a,b) for(int i = a;i <= b; i++)
#define mp(a,b) make_pair(a,b)
using namespace std;
priority_queue<pair<int, int> >q;
struct node {
int next;
int to;
int w;
} a[500001];
int n, head[500001], cnt = 1, m, s;
int vis[500001];
int ans[500001];
int jl[500005];
void ru(int x, int y, int z) {
a[cnt].to = y;
a[cnt].w = z;
a[cnt].next = head[x];
head[x] = cnt++;
}
int main() {
int x, y, z;
scanf("%d%d%d", &n, &m, &s);
for1(i, 1, m) {
scanf("%d%d%d", &x, &y, &z);
ru(x, y, z);
}
for1(i, 1, n) ans[i] = 2147483647;
ans[s] = 0;
q.push(mp(0, s));
while (!q.empty()) {
int x = q.top().second;
q.pop();
if (vis[x] == 1)
continue;
vis[x] = 1;
for (int i = head[x]; i != 0; i = a[i].next) {
if (ans[a[i].to] > ans[x] + a[i].w) {
jl[a[i].to] = x;
ans[a[i].to] = ans[x] + a[i].w;
q.push(mp(-ans[a[i].to], a[i].to));
}
}
}
int ciduan = ans[n];
for (int i = n; i != 1; i = jl[i]) {
int sy = i, sx = jl[i];
for1(i, 1, n) ans[i] = 2147483647;
ans[s] = 0;
q.push(mp(0, s));
for1(i, 1, n) vis[i] = 0;
while (!q.empty()) {
int x = q.top().second;
q.pop();
if (vis[x] == 1)
continue;
vis[x] = 1;
for (int i = head[x]; i != 0; i = a[i].next) {
if (x == sx && a[i].to == sy)
continue;
if (ans[a[i].to] > ans[x] + a[i].w) {
jl[a[i].to] = x;
ans[a[i].to] = ans[x] + a[i].w;
q.push(mp(-ans[a[i].to], a[i].to));
}
}
if (ans[n] != 2147483647)
ciduan = max(ans[n], ciduan);
}
}
cout << ciduan << endl;
return 0;
}
loj 119. 单源最短路(Floyd)(80):
#include<bits/stdc++.h>
#define for1(i,a,b) for(ll i = a;i <= b; i++)
#define mp(a,b) make_pair(a,b)
#define ll long long
using namespace std;
const ll inf = 99999999;
ll a[15000][15000],n,m,s,t;
int main()
{
ll x,y,z;
scanf("%lld%lld%lld%lld",&n,&m,&s,&t);
for1(i,1,n)
for1(j,1,n)
if(i==j) a[i][j]=0;
else a[i][j]=inf;
for1(i,1,m)
{
scanf("%lld%lld%lld",&x,&y,&z);
a[x][y]=z;
a[y][x]=z;
}
for1(k,1,n)
for1(i,1,n)
for1(j,1,n)
a[i][j] = min(a[i][j], a[i][k]+a[k][j]);
printf("%lld ",a[s][t]);
return 0;
}
P4017 最大食物链计数(拓扑):
#include<bits/stdc++.h>
using namespace std;
struct node{
int to;
int nex;
}a[500005];
int n,hd[500005],an[500005],cnt=1,m,in[500005],ans;
bool out[500005];
const int md=80112002;
queue <int> q;
void ru(int x,int y)
{
a[cnt].to=y;
a[cnt].nex=hd[x];
hd[x]=cnt++;
}
int main()
{
int x,y;
scanf("%d%d",&n,&m);
for(int i = 1;i <=m;i++)
{
scanf("%d%d",&x,&y);
ru(x,y);
in[y]++;
out[x]++;
}
for(int i =1;i <=n;i++)
if(in[i]==0)
{
q.push(i);
an[i]=1;
}
while(!q.empty())
{
int r = q.front();
q.pop();
for(int i=hd[r];i!=0;i=a[i].nex)
{
int w=a[i].to;
an[w]=(an[w]+an[r])%md;
in[w]--;
if(in[w]==0) q.push(w);
}
}
for(int i = 1;i <= n;i++)
if(out[i]==0)
ans=(ans+an[i])%md;
printf("%d",ans);
return 0;
}
P3386 【模板】二分图最大匹配(匈牙利算法)
#include<bits/stdc++.h>
#define ll long long
#define for1(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
int n,m,e,tu[5005][5005],vis[500005],match[500005],ans;//match[i]存储第i个点的配对的点(如果没配对过就是0)
//vis[i]表示右侧第i个点有没有被访问过
bool nly(int x)//寻找x是否有能配对的边
{
for1(i,1,m)//枚举所有的边
{
if(tu[x][i]==1&&!vis[i])//如果没有查询过并且有边相连接
{
vis[i]=1;
if(!match[i]||nly(match[i]))//如果i没有配对,i就与x配对,如果i配对了,则尝试能否让i配对的点去寻找另一个点去配对
{
match[i]=x;
return 1;
}
}
}
return 0;
}
int main()
{
int x,y;
scanf("%d%d%d",&n,&m,&e);
for1(i,1,e)
{
scanf("%d%d",&x,&y);
tu[x][y]=1;
}
for1(i,1,n)
{
ans+=nly(i);
for1(j,1,n) vis[j]=0;
}
cout<<ans<<endl;
return 0;
}
P5960 【模板】差分约束算法
#include<bits/stdc++.h>
#define ll long long
#define for1(i,a,b) for(int i=a;i<=b;i++)
const int inf=1e9;
using namespace std;
struct node{
int to;
int nex;
int w;
}a[500005];
int n,m,hd[500005],cnt,vis[500005],dis[500005],num[500005];//1表示在队列中
queue < int > dl;
void ru(int x,int y,int z)
{
a[++cnt].to=y;
a[cnt].w=z;
a[cnt].nex=hd[x];
hd[x]=cnt;
return ;
}
bool spfa()
{
while(!dl.empty())
{
int x=dl.front();
dl.pop();
vis[x]=0;
for(int i = hd[x];i;i=a[i].nex)
{
int y=a[i].to;
if(dis[y]>dis[x]+a[i].w)
{
dis[y]=dis[x]+a[i].w;
if(vis[y]==0)
{
vis[y]=1;
dl.push(y);
num[y]++;
if(num[y]>n+1) return 1;
}
}
}
}
return 0;
}
int main()
{
int x,y,z;
scanf("%d%d",&n,&m);
for1(i,1,m)
{
scanf("%d%d%d",&x,&y,&z);
ru(y,x,z);
}
for1(i,1,n)
ru(0,i,0);
for1(i,1,n) dis[i]=inf;
dis[0]=0;
dl.push(0);
num[0]++;
vis[0]=1;
if(spfa()==1) cout<<"NO"<<endl;
else
for1(i,1,n)
printf("%d ",dis[i]);
return 0;
}
P4782 【模板】2-SAT 问题
首先每个bool都开两个结点,然后对于每个情况连边,(如a->非b,意思是若选a为真就要选b为假),之后tarjan跑一趟,如果发现有一个bool的真与假出现在同强连通分量,就代表无解,如果有解那么就按拓扑序输出,由于tarjan的dfn序就是逆拓扑序(我也不知道为什么),所以就直接比较每一个bool的真假两个节点的dfn序,输出大的那个
#include<bits/stdc++.h>
#define for1(i,a,b) for(int i = a;i<=b;i++)
#define ll long long
#define mp(a,b) make_pair(a,b)
using namespace std;
int n,m,ji,b,x,y,t,top,cnt,cnt2;
int dfn[4000005],low[4000005],st[4000005],vis[4000005],col[4000005],head[4000005];
struct node{
int to,nex;
}a[4000005];
void ru(int from,int to)
{
cnt++;
a[cnt].nex=head[from];
a[cnt].to=to;
head[from]=cnt;
}
void tarjan(int u)
{
dfn[u]=low[u]=++t;
st[++top]=u;
vis[u]=1;
for(int i=head[u];i;i=a[i].nex)
{
int v=a[i].to;
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])
{
cnt2++;
while(st[top]!=u)
{
col[st[top]]=cnt2;
vis[st[top]]=0;
top--;
}
col[st[top]]=cnt2;
vis[st[top]]=0;
top--;
}
}
int main()
{
cin>>n>>m;
for1(i,1,m)
{
cin>>ji>>x>>b>>y;
if(x==0&&y==0)
{
ru(ji+n,b);
ru(b+n,ji);
}
if(x==0&&y==1)
{
ru(ji+n,b+n);
ru(b,ji);
}
if(x==1&&y==0)
{
ru(ji,b);
ru(b+n,ji+n);
}
if(x==1&&y==1)
{
ru(ji,b+n);
ru(b,ji+n);
}
}
for1(i,1,n*2)
if(!dfn[i])
tarjan(i);
for1(i,1,n)
if(col[i]==col[i+n])
{
puts("IMPOSSIBLE");
return 0;
}
puts("POSSIBLE");
for1(i,1,n)
{
if(col[i]>col[i+n]) printf("1 "); //tarjan求出了拓扑反序
else printf("0 ");
}
return 0;
}
P7771 【模板】欧拉路径
#include<bits/stdc++.h>
#define for1(i,a,b) for(int i = a;i<=b;i++)
#define ll long long
using namespace std;
struct node{
int from;
int to;
int nex;
}a[500005];
struct bian{
int from;
int to;
}b[500005];
int cnt,n,m,hd[500005],in[500005],out[500005],skg,tkg,jis,jit,pd;
int zhan[500005],top;
void ru(int x,int y)
{
a[++cnt].to=y;
a[cnt].nex=hd[x];
hd[x]=cnt;
}
bool cmp(bian x,bian y)
{
return x.from==y.from?x.to>y.to:x.from>y.from;
}
void dfs(int now)
{
for(int i = hd[now];i;i=hd[now])
{
int v=a[i].to;
hd[now]=a[i].nex;
dfs(v);
}
zhan[++top]=now;
}
int main()
{
int x,y;
scanf("%d%d",&n,&m);
for1(i,1,m) scanf("%d %d",&b[i].from,&b[i].to);
sort(b+1,b+m+1,cmp);
for1(i,1,m) ru(b[i].from,b[i].to),in[b[i].to]++,out[b[i].from]++;
for1(i,1,n)
{
if(in[i]+1==out[i]) skg++,jis=i;
if(in[i]==out[i]+1) tkg++,jit=i;
if(in[i]==out[i]) pd++;
}
if(skg==1&&tkg==1&&pd==n-2)//有欧拉路径
{
dfs(jis);
for(int i =top;i>=1;i--) cout<<zhan[i]<<' ';
}
else if(pd==n)//有欧拉路回路
{
dfs(1);
for(int i =top;i>=1;i--) cout<<zhan[i]<<' ';
}
else puts("No");
return 0;
}
全局最小割 P5632 【模板】Stoer-Wagner算法
luogu上的题解讲得都比较抽象,我找了一个好一点的
https://www.cnblogs.com/JiaZP/p/13300187.html
#include<bits/stdc++.h>
#define ll long long
#define for1(i,a,b) for(register ll i = a;i <= b;i ++)
using namespace std;
const ll maxn = 5e3 + 5;
ll n,dis[maxn][maxn],ord[maxn],w[maxn],vis[maxn],dap[maxn];
ll s,t,m;
int cl(int x)
{
memset(vis,0,sizeof(vis));
memset(w,0,sizeof(w));
w[0] = -1;
for1(i,1,n-x + 1)
{
int mx = 0;
for1(j,1,n)
if(!dap[j] && !vis[j] && w[j] > w[mx])
mx = j;
vis[mx] = 1;
ord[i] = mx;
for1(j,1,n)
if(!dap[j] && !vis[j])
w[j] += dis[mx][j];
}
s = ord[n - x];
t = ord[n - x + 1];
//此时st就是最后加入的两个点w[t]就是这个st的最小割
return w[t];
}
int sw()
{
int res = 1e9;
for1(i,1,n - 1)
{
res = min(res,cl(i));
dap[t] = 1;//代表已经算过了
for1(j,1,n)
{
dis[s][j] += dis[t][j];
dis[j][s] += dis[j][t];
}
}
return res;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cin >> n >> m;
int x,y,z;
for1(i,1,m)
{
cin >> x >> y >> z;
dis[x][y] += z;
dis[y][x] += z;
}
cout <<sw() << '\n';
return 0;
}
P6086 【模板】Prufer 序列
还有个序列转树的,本质上没有区别
#include<bits/stdc++.h>
#define for1(i,a,b) for(register ll i = a;i <= b; i++)
#define ll long long
using namespace std;
const int maxn = 6e6 + 5;
const int mod = 1e9 + 7;
ll n, ji, f[maxn], p[maxn], d[maxn];
ll ans;
void cl1()
{
for1(i,1,n - 1)
cin >> f[i],
++d[f[i]];
for (int i = 1, pos = 1; i <= n - 2; i++, pos++)
{
while (d[pos] != 0)
pos++;
p[i] = f[pos];
while (i <= n - 2 && !--d[p[i]] && p[i] < pos)
p[i+1] = f[p[i]],
i ++;
}
for1(i,1,n - 2)
ans ^= 1ll * i * p[i];
}
void cl2()
{
for1(i,1,n - 2)
cin >> p[i],
d[p[i]] ++ ;
p[n - 1] = n;
for (int i = 1, pos = 1; i < n; i++, pos++)
{
while (d[pos] != 0)
pos++;
f[pos] = p[i];
while (i < n && !--d[p[i]] && p[i] < pos)
f[p[i]] = p[i+1],
i ++;
}
for1(i,1,n - 1)
ans ^= i * f[i];
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> n >> ji;
if(ji == 1)
cl1();
else
cl2();
cout << ans << '\n';
return 0;
}
点分治 P3806 【模板】点分治1
#include<bits/stdc++.h>
#define ls q << 1
#define rs q << 1 | 1
#define ll long long
#define for1(i,a,b) for(int i = a;i <= b;i++)
using namespace std;
const int maxn = 5e4 + 5;
const int inf = 1e8 + 7;
struct node{
int nex;
int to;
int w;
}a[maxn<<1];
int hd[maxn],cnt;
int rt;//重心
struct ask{
int val;
int ans;
}ask[maxn];
int siz[maxn],mxp[maxn],dis[maxn],rem[maxn],ji[maxn];
bool jud[inf];
int sum,vis[maxn],n,m;
void ru(int x, int y, int z)
{
a[++cnt].to = y;
a[cnt].w = z;
a[cnt].nex = hd[x];
hd[x] = cnt;
}
void getrt(int x, int fa)//找重心
{
siz[x] = 1;
mxp[x] = 0;
for(int i = hd[x];i;i = a[i].nex)
{
int v = a[i].to;
if(v == fa || vis[v] == 1) continue;
getrt(v,x);
siz[x] += siz[v];
mxp[x] = max(mxp[x],siz[v]);
}
mxp[x] = max(mxp[x],sum - siz[x]);//向上的子树
if(mxp[x] < mxp[rt]) rt = x;
}
void getdis(int x, int fa)
{
rem[0]++;
rem[rem[0]] = dis[x];
for(int i = hd[x];i;i = a[i].nex)
{
int v = a[i].to;
if(v == fa || vis[v] == 1) continue;
dis[v] = dis[x] + a[i].w;
getdis(v,x);
}
}
void cl(int x)
{
int p = 0;
for(int i = hd[x];i;i = a[i].nex)
{
int v = a[i].to;
if(vis[v] == 1) continue;
rem[0] = 0;
dis[v] = a[i].w;
getdis(v,x);//计算子树答案
for1(j,1,rem[0])//统计
for1(k,1,m)
if(ask[k].val >= rem[j])
ask[k].ans |= jud[ask[k].val - rem[j]];
for1(j,1,rem[0])//插入jud数组
ji[++p] = rem[j],jud[rem[j]] = 1;
}
for1(i,1,p)//清零
jud[ji[i]] = 0;
}
void solve(int x)
{
vis[x] = jud[0] = 1;
cl(x);
for(int i = hd[x];i;i = a[i].nex)
{
int v = a[i].to;
if(vis[v] == 1) continue;
sum = siz[v];
rt = 0;
mxp[rt] = 1e9 + 7;
getrt(v,0);
solve(rt);
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cin >> n >> m;
int x,y,z;
for1(i,1,n - 1)
{
cin >> x >> y >> z;
ru(x,y,z);
ru(y,x,z);
}
for1(i,1,m)
cin >> ask[i].val;
mxp[rt] = sum = n;
getrt(1,0);
solve(rt);
for1(i,1,m) cout << (ask[i].ans != 0 ?"AYE\n":"NAY\n");
return 0;
}

浙公网安备 33010602011771号