图论

目录

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;
}

posted @ 2022-02-17 11:38  yyx525jia  阅读(20)  评论(0)    收藏  举报