-->

2023五一外出学习整理(图论

Day1:

上午:

引入:

 对任意两个元素a,b之间关系(a,b)的取值仅为 True 或者 False,可以考虑使用图来抽象。这样我们称一个元素 a 为一个结点,(a,b)== True 则称结点 a,b 间有连边,否则 a,b 间没有连边。

 问题转化:一张奇数个点的图 G,证明存在一个点度数为偶数。

转化为更强的问题为:给定一张奇数个点的图 G,证明度数为偶数的点的个数为奇数。

(相反的问题:给定一张奇数个点的图 G,证明度数为奇数的结点的个数为偶数。)

证明:考虑所有点的度数和,由于一条边会被计算到两个结点的度数上,故其必定为偶数。(小学数学易得结论?)

 

Ex.1:首先可证 n-1 个点与除它之外 n-2 个点连边所以可连 (n-1)(n-2)/2 条边,因此可得 n 个点和至少 ((n-1)(n-2)/2)+1 条边的图是连通图。

Ex.2:

 由图可得,对于任意一个图,可将其分为若干个连通块,连通块内部各点都相连,因此其补图原来的连通块内各点于其他各连通块各点相连,因此一定是联通的。

Ex.3:

任意两边至少有一个点是重合的,即为如图:

 因此当为完全图时,每点度数>=2,因此不可能为星星,反之亦然。

Ex.4:***

Ex.5:分类讨论,

当存在度数为一的点时,删掉度数为一的点剩下的图依旧是连通图。

当不存在时,选择任意一点为起点,计算其他点与起点的距离,删掉距离起点最远的点后,图依旧为连通图。

欧拉回路和哈密顿回路:

1)考虑一个度数为奇数的点,因为它的所有邻边均要遍历恰好一次,故其必须为欧
拉路径的起点或终点。因此可以立即推出,一张存在欧拉路径的图恰好有两个度数为奇数
的点,存在欧拉回路的图没有度数为奇数的点。

2)任意两个回路,可以拼成一个大的回路。

由这两个观察可以发现,Fact 1是存在欧拉路径或者欧拉回路的充要条件。

反证法,假设没有哈密顿回路。

我们由图 G 构造出一个新的没有哈密顿回路的图 G',具体的,令 G'=G,对于每条不在图 G 中的边,如果加入 G' 后不会产生哈密顿回路,则加入,该构造的顺序不重要。

此时我们得到了一个图 G',再加入任何一条边都会得到一条哈密顿回路,并且由于我们仅加入了新的边,所有结点的度数任然大于等于 n/2。

假设 (v1,vn) 这条边不在 G' 中,我们知道必定存在一条哈密顿路径 v1,v2,...,v考虑 (v1,vi) 有一条边,则 (vi-1,vn) 必定不能有边,否则可以构造出一条哈密顿回路。

因为这样的 vi 至少有 n/2 个,从而这样的 vi-1 也至少有 n/2 个,又由于 vn 不能和自己连边,故而它至多与 n-n/2-1 个点连边,<=n/2 ,因此与定理矛盾,因此假设不成立。

Ex.6:因为两数互质,因此间隔至少为2,又因为有 n+1,个小于等于 2n 的正整数,所以显然,存在两个数互质。

Ex.7:...

Ex.8:将棋盘进行黑白染色和蓝红染色

Ex.9:Luogu P1341

 1 //By:Komorebi_03
 2 #include<bits/stdc++.h>
 3 using namespace std;
 4 #define clear(a) memset(a,0,sizeof a)
 5 #define ll long long
 6 const int N = 1e3+5;
 7 int n,sum,dis[N][N];
 8 char in[N],a[N];
 9 inline int read()
10 {
11     int x=0,f=1;char ch=getchar();
12     while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
13     while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
14     return x*f;
15 }
16 
17 void Find(int i)
18 {
19     for (int j=1;j<=150;j++)
20     {
21         if(dis[i][j]>0)
22         {
23             dis[i][j]--;
24             dis[j][i]--;
25             Find(j);
26         }
27     }
28     a[++sum]=i;
29     return ;
30 }
31 
32 int main()
33 {
34     n=read();
35     for (int i=1;i<=n;i++)
36     {
37         string s;
38         cin>>s;
39         dis[s[0]][s[1]]++;
40         dis[s[1]][s[0]]++;
41         in[s[0]]++;
42         in[s[1]]++;
43     }
44     int h=0;
45     int cnt=0;
46     for (int i=1;i<=150;i++)
47     {
48         if(in[i] & 1)
49         {
50             cnt++;
51             if(!h)
52                 h=i;
53         }
54     }
55     if(!h)
56     {
57         for (int i=0;i<150;i++)
58         {
59             if(in[i])
60             {
61                 h=i;
62                 break;
63             }
64         }
65     }
66     if(cnt && cnt!=2)
67     {
68         cout<<"No Solution";
69         exit(0);
70     }
71     Find(h);
72     if(sum<n+1)
73     {
74         cout<<"No Solution";
75         exit(0);
76     }
77     for(int i=sum;i>=1;i--)
78         cout<<a[i];
79     return 0;
80     //Amireux_35
81 }
P1341

图的储存和遍历:

 1)邻接矩阵: .........没啥可说的

2)邻接表:

vector :

 1 #include <vector>
 2 vector<int> Edge[1000];
 3 // Edge[i] 是一个一维数组,存了所有 i 能到的点
 4 void add(int u, int v) // 插入一条 (u,v) 的边
 5 {
 6     Edge[u].push_back(v);
 7     Edge[v].push_back(u);
 8 }
 9 void search(int u) // 遍历 u 的所有邻边
10 {
11     for ( int i = 0; i < Edge[u].size(); i++ )
12     //Edge[u].size() 是unsigned int,0-1=2^32-1
13     {
14         int v = Edge[u][i];
15         //(u,v) 有一条边
16         ......
17     }
18 }
vector

链式前向星:

 1 int Begin[1000], Next[1000], To[1000], e;
 2 void add(int u, int v) // 插入一条 (u,v) 的边
 3 {
 4     To[++ e] = v;
 5     Next[e] = Begin[u];
 6     Begin[u] = e;
 7 }
 8 void search(int u)
 9 {
10     for ( int i = Begin[u]; i; i = Next[i] ) // 遍历 u 的所有邻边
11     {
12         int v = To[i];
13         ...
14     }
15 }
链式前向星

注:这是ljf的代码,本人等习惯用结构体。

Ex.10:CF 1472C

 1 //By:Komorebi_03
 2 #include<bits/stdc++.h>
 3 using namespace std;
 4 #define ll long long
 5 const int N = 1e6+5;
 6 int T,n,a[N];
 7 bool vis[N];
 8 vector<int> edge[N];
 9 inline int read()
10 {
11     int x=0,f=1;char ch=getchar();
12     while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
13     while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
14     return x*f;
15 }
16 
17 int dfs(int u)
18 {
19     if(u>n || vis[u])
20         return 0;
21     vis[u]=true;
22     if(edge[u].size()==1)
23         return a[u]+dfs(edge[u][0]);
24     return a[u];
25 }
26 
27 int main()
28 {
29     T=read();
30     while (T--)
31     {
32         int ans=0;
33         n=read();
34         for (int i=1;i<=n;i++)
35         {
36             vis[i]=false;
37             edge[i].clear();
38         }
39         for (int i=1;i<=n;i++)
40         {
41             cin>>a[i];
42             edge[i].push_back(i+a[i]);
43         }
44         for (int i=1;i<=n;i++)
45             ans=max(ans,dfs(i));
46         cout<<ans<<"\n";
47     }
48     return 0;
49     //Amireux_35
50 }
CF 1472C

二分图:

 显然,二分图 G 存在完美匹配的必要条件是 ιAι = ιBι

 

匈牙利算法

Ex.11:Luogu P3386

 1 //By:Komorebi_03
 2 #include<bits/stdc++.h>
 3 using namespace std;
 4 #define ll long long
 5 const int N = 1e6+5;
 6 int n,m,p,ans,cnt,e_cnt,sum[N],dfn[N],head[N];
 7 struct node{
 8     int v;
 9     int nxt;
10 }e[N];
11 inline int read()
12 {
13     int x=0,f=1;char ch=getchar();
14     while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
15     while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
16     return x*f;
17 }
18 
19 void add(int u,int v)
20 {
21     e[++e_cnt].v=v;
22     e[e_cnt].nxt=head[u];
23     head[u]=e_cnt;
24 }
25 
26 bool dfs(int u,int t)
27 {
28     for (int i=head[u];i;i=e[i].nxt)
29     {
30         int v=e[i].v;
31         if(dfn[v]!=t)
32         {
33             dfn[v]=t;
34             if(!sum[v] || dfs(sum[v],t))
35             {
36                 sum[v]=u;
37                 return true;
38             }
39         }
40     }
41     return false;
42 }
43 
44 int main()
45 {
46     n=read();
47     m=read();
48     p=read();
49     for (int i=1;i<=p;i++)
50     {
51         int u=read();
52         int v=read();
53         if(u>n || v>m)
54             continue;
55         add(u,v);
56     }
57     for (int i=1;i<=n;i++)
58         if(dfs(i,++cnt))
59             ans++;
60     cout<<ans;
61     return 0;
62 }
Luogu P3386

Ex.12:CF 1764C

 1 //By:Komorebi_03
 2 #include<bits/stdc++.h>
 3 using namespace std;
 4 #define clear(a) memset(a,0,sizeof a)
 5 #define int long long
 6 const int N = 1e6+5;
 7 int T,n,a[N],sum[N];
 8 inline int read()
 9 {
10     int x=0,f=1;char ch=getchar();
11     while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
12     while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
13     return x*f;
14 }
15 
16 signed main()
17 {
18     T=read();
19     while (T--)
20     {
21         int cnt=0;
22         int ans=0;
23         n=read();
24         for (int i=1;i<=n;i++)
25         {
26             a[i]=read();
27             sum[a[i]]++;
28         }
29         sort(a+1,a+1+n);
30         for (int x=1;x<=n;x++)
31         {
32             if(a[x]==a[x-1])
33                 continue;
34             cnt+=sum[a[x]];
35             if(cnt==n)
36                 ans=max(ans,n/2);
37             else
38                 ans=max(ans,cnt*(n-cnt));
39         }
40         cout<<ans<<"\n";
41         for (int i=1;i<=n;i++)
42             sum[a[i]]--;
43 //        memset(sum,0,sizeof sum);
44     }
45     return 0;
46     //Amireux_35
47 }
CF 1764C

一份 vector 的使用说明:

 1 #include <vector> // 头文件
 2 vector<int> a; // 等价于定义一个 int a[] 的数组
 3 int a[100];
 4 vector<int> a(100);
 5 printf("%d\n", a.size()); // 100
 6 a.push_back(1);
 7 printf("%d\n", a.size()); // 101
 8 a.push_back(x); // 在 a 的最末尾插入一个值为 x 的元素
 9 a[i] // 访问 a 的第 i 个元素
10 a.size() // 返回 a 的元素个数(类型为 unsigned int)
11 a.pop() // 移除 a 的最末尾的元素
12 a.empty() // 返回 a 的 size 是否非零 (True or False)
13 a.resize(10) // 修改 a 的 size 为 10
vector 使用说明

下午:(树)

 基本知识:

直观上来说,树等价于没有环的连通图。

树有非常好的性质:

1)任意两点间存在唯一的路径,不存在回路。

2)树一定存在叶结点,即 deg==1 的结点。

树作为一种特殊的图,研究他的重要意义是,在这些特殊性质下,我们可以解决一些在图中无法解决的问题。------ljf

树的储存通常使用与图相同的储存方式,而遍历通常使用DFS

 1 DFS(root, 0); // root 表示整棵树的根
 2 
 3 void DFS(int u, int from)
 4 {
 5     ......
 6     for ( int i = 0; i < Edge[u].size(); ++i )
 7     {
 8         int v = Edge[u][i];
 9         if ( v == from )
10             continue ;
11         DFS(v, u);
12     }
13     ......
14 }
DFS遍历树

Ex.1:CF 522A

 1 //By:Komorebi_03
 2 #include<bits/stdc++.h>
 3 using namespace std;
 4 #define clear(a) memset(a,0,sizeof a)
 5 #define ll long long
 6 const int N = 401;
 7 int n,cnt,ans,dep[N];
 8 string a,b;
 9 map<string,int> mp;
10 vector<vector<int>> g;
11 inline int read()
12 {
13     int x=0,f=1;char ch=getchar();
14     while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
15     while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
16     return x*f;
17 }
18 
19 void change(string &a)
20 {
21     int len=a.size();
22     for (int i=0;i<len;i++)
23     {
24         if(a[i]>='A' && a[i]<='Z')
25         {
26             a[i]-='A';
27             a[i]+='a';
28         } 
29     }
30 }
31 
32 void dfs(int x)
33 {
34     for (int i=0;i<g[x].size();i++)
35     {
36         int v=g[x][i];
37         dep[v]=dep[x]+1;
38         dfs(v);
39     }
40     ans=max(ans,dep[x]);
41 }
42 
43 int main()
44 {
45     n=read();
46     g.resize(2*n+3);
47     for (int i=1;i<=n;i++)
48     {
49         cin>>a>>b>>b;
50         change(a);
51         change(b);
52         if(!mp.count(a))
53             mp[a]=++cnt;
54         if(!mp.count(b))
55             mp[b]=++cnt;
56         g[mp[a]].push_back(mp[b]);
57     }
58     for (int i=1;i<=cnt;i++)
59     {
60         if(!dep[i])
61         {
62             dep[i]=1;
63             dfs(i);
64         }
65     }
66     cout<<ans;
67     return 0;
68     //Amireux_35
69 }
CF 522A

Ex.2:CF 115A

 1 //By:Komorebi_03
 2 #include<bits/stdc++.h>
 3 using namespace std;
 4 #define clear(a) memset(a,0,sizeof a)
 5 #define ll long long
 6 const int N = 1e6+5;
 7 int n,ans,fa[N];
 8 inline int read()
 9 {
10     int x=0,f=1;char ch=getchar();
11     while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
12     while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
13     return x*f;
14 }
15 
16 int Find(int x)
17 {
18     int cnt=0;
19     while (x!=-1)
20     {
21         x=fa[x];
22         cnt++;
23     }
24     return cnt;
25 }
26 
27 int main()
28 {
29     n=read();
30     for (int i=1;i<=n;i++)
31         fa[i]=read();
32     for (int i=1;i<=n;i++)
33         ans=max(ans,Find(i));
34     cout<<ans;
35     return 0;
36     //Amireux_35
37 }
CF 115A

直径和重心:

称树的直径为树上最长的一条路径,树的重心为 删去这个点后,最大的子树最小

 1 int DFS(int u, int from)
 2 {
 3     int Max = 0, Maxx = 0;
 4     for ( int i = 0; i < Edge[u].size(); ++ i )
 5     {
 6         int v = Edge[u][i];
 7         if ( v == from ) continue ;
 8         int dis = DFS(v, u);
 9         if ( dis > Max ) { Maxx = Max; Max = dis; }
10         else if ( dis > Maxx ) Maxx = dis;
11     }
12     ans = max(ans, Max + Maxx + 1);
13     return Max + 1;
14 }
树的直径
 1 int ans = n + 1, pos = 0;
 2 int DFS(int u, int from)
 3 {
 4     int size = 1, Max = 0;
 5     for ( int i = 0; i < Edge[u].size(); ++ i )
 6     {
 7         int v = Edge[u][i];
 8         if ( v == from ) continue ;
 9         int x = DFS(v, u);
10         size += x;
11         Max = max(Max, x);
12     }
13     Max = max(Max, n - size);
14     if ( Max < ans ) { ans = Max, pos = u; }
15     return size;
16 }
树的重心

Ex.3:CF 690C2

 1 //By:Komorebi_03
 2 #include<bits/stdc++.h>
 3 using namespace std;
 4 #define clear(a) memset(a,0,sizeof a)
 5 #define ll long long
 6 const int N = 1e6+5;
 7 int n,m,p,ans,e_cnt,dis[N],head[N];
 8 struct node{
 9     int v;
10     int nxt;
11 }e[N];
12 inline int read()
13 {
14     int x=0,f=1;char ch=getchar();
15     while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
16     while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
17     return x*f;
18 }
19 
20 void add(int u,int v)
21 {
22     e[++e_cnt].v=v;
23     e[e_cnt].nxt=head[u];
24     head[u]=e_cnt;
25 }
26 
27 void dfs(int u,int frm)
28 {
29     int Max=0;
30     int Maxx=0;
31     for (int i=head[u];i;i=e[i].nxt)
32     {
33         int v=e[i].v;
34         if(v==frm)
35             continue;
36         dfs(v,u);
37         int w = dis[v]+1;
38         dis[u]=max(dis[u],w);
39         if(w>Max)
40         {
41             Maxx=Max;
42             Max=w;
43         }
44         else if (w>Maxx)
45             Maxx=w;
46     }
47     ans=max(ans,Max+Maxx);
48     }
49 
50 int main()
51 {
52     n=read();
53     m=read();
54     for (int i=1;i<=m;i++)
55     {
56         int u=read();
57         int v=read();
58         add(u,v);
59         add(v,u);
60     }
61     dfs(1,0);
62     cout<<ans;
63     return 0;
64 }
CF 690C2

 

最近公共祖先:

 倍增算法

 1 int LCA(int u, int v)
 2 {
 3     if ( dis[u] < dis[v] ) swap(u,v);
 4     for ( int j = 20; j >= 0; -- j )
 5         if ( dis[f[u][j]] >= dis[v] ) u = f[u][j];
 6     if ( u == v ) return u;
 7     for ( int j = 20; j >= 0; -- j )
 8         if ( f[u][j] != f[v][j] ) { u = f[u][j]; v = f[v][j]; }
 9     return f[u][0];
10 }
11 void INIT()
12 {
13     DFS(); // 使用 DFS 处理好 f[u][0] 和 dis[u]
14     for ( int j = 1; j <= 20; ++ j )
15         for ( int i = 1; i <= n; ++ i )      
16             f[i][j] = f[f[i][j - 1]][j - 1];
17 }
倍增

Tarjan算法

 1 void DFS(int u, int from)
 2 {
 3     vis[u] = true;
 4     for ( int i = 0; i < Edge[u].size(); ++ i )
 5     {
 6         int v = Edge[u][i];
 7         if ( v == from ) continue ;
 8         DFS(v, u);
 9         Merge(u, v); // 并查集
10     }
11     for ( int i = 0; i < query[u].size(); ++ i ) // 在 u 点的查询列表
12     {
13         int v = query[u][i];
14         if ( vis[v] == true ) ans[u][v] = Find(v); 
15         //u,v 的查询答案是Find(v)
16     }
17 }
Tarjan算法

其它:

满二叉树是一种特殊的树,所有非叶结点都恰有两个子结点,它拥有更加优秀的性质:

Ex.4:CF 1741D

 1 //By:Komorebi_03
 2 #include<bits/stdc++.h>
 3 using namespace std;
 4 #define clear(a) memset(a,0,sizeof a)
 5 #define ll long long
 6 const int N = 1e6+5;
 7 int T,n,a[N];
 8 inline int read()
 9 {
10     int x=0,f=1;char ch=getchar();
11     while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
12     while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
13     return x*f;
14 }
15 
16 int main()
17 {
18     T=read();
19     while (T--)
20     {
21         n=read();
22         clear(a);
23         for (int i=1;i<=n;i++)
24             a[i]=read();
25         int cnt=0;
26         bool flag=false;
27         for (int i=2;i<=n;i<<=1)
28         {
29             for (int j=i;j<=n;j+=i)
30             {
31                 if(a[j-(i>>1)]>a[j])
32                 {
33                     swap(a[j-(i>>1)],a[j]);
34                     cnt++;
35                 }
36                 if(a[j-(i>>1)]+(i>>1)!=a[j])
37                 {
38                     cout<<-1<<"\n";
39                     flag=true;
40                     break;
41                 }
42             }
43             if(flag)
44                 break;
45         }
46         if(flag)
47             continue;
48         cout<<cnt<<"\n";
49     }
50     return 0;
51     //Amireux_35
52 }
53 
54 /*
55   你考虑根左子树的数集合是A
56   右子树的数集合是B
57   那么无论你左右子树内部怎么转
58   这个集合是不会变的
59   所以你只有可能通过根的交换
60   来换A,B这两个完整的集合
61   所以有解当且仅当
62   A,B集合有一个全是小的数
63   另外一个全是大的数
64   然后递归做这个问题就行
65  */
CF 1741D

Ex.5:CF 1675D

 1 // Problem: CF1675D Vertical Paths
 2 // Contest: Luogu
 3 // URL: https://www.luogu.com.cn/problem/CF1675D
 4 // Memory Limit: 250 MB
 5 // Time Limit: 2000 ms
 6 // 
 7 // Powered by CP Editor (https://cpeditor.org)
 8 
 9 //By:Komorebi_03
10 #include<bits/stdc++.h>
11 using namespace std;
12 #define clear(a) memset(a,0,sizeof a)
13 #define ll long long
14 const int N = 2e6+5;
15 int T,n,ans,y[N],p[N],sum[N];
16 bool vis[N];
17 inline int read()
18 {
19     int x=0,f=1;char ch=getchar();
20     while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
21     while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
22     return x*f;
23 }
24 
25 int main()
26 {
27     T=read();
28     while (T--)
29     {
30         ans=0;
31         n=read();
32         for (int i=1;i<=n;i++)
33         {
34             vis[i]=false;
35             y[i]=1;
36         }
37         for (int i=1;i<=n;i++)
38         {
39             p[i]=read();
40             if(p[i]!=i)
41                 y[p[i]]=0;
42         }
43         for (int i=1;i<=n;i++)
44             if(y[i])
45                 ans++;
46         cout<<ans<<"\n";
47         for (int i=1;i<=n;i++)
48         {
49             if(y[i])
50             {
51                 int now=i;
52                 int cnt=0;
53                 while (!vis[now])
54                 {
55                     sum[++cnt]=now;
56                     vis[now]=true;
57                     if(p[now]==now)
58                         break;
59                     now=p[now];
60                 }
61                 cout<<cnt<<"\n";
62                 for (int j=cnt;j>=1;j--)
63                     cout<<sum[j]<<" ";
64                 putchar('\n');
65             }
66         }
67         putchar('\n');
68     }
69     return 0;
70     //Amireux_35
71 }
CF 1675D

 


 

Day2:

上午:

生成树问题:

DFS生成树:

对于任意一棵DFS生成树,其必定只有返祖边,没有横叉边,在求割点和强连通分量上方便很多。

CF 1104E

CF 1726D

  1 //By:Komorebi_03
  2 #include<bits/stdc++.h>
  3 using namespace std;
  4 const int N = 2e6+10;
  5 int T,n,m,pre,flag,u[N],v[N],du[N],fa[N];
  6 inline int read()
  7 {
  8     int x=0,f=1;char ch=getchar();
  9     while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
 10     while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
 11     return x*f;
 12 }
 13 
 14 int Find(int x)
 15 {
 16     if(fa[x]==x)
 17         return x;
 18     return fa[x]=Find(fa[x]);
 19 }
 20 
 21 void init()
 22 {
 23     for (int i=1;i<=n;i++)
 24     {
 25         fa[i]=i;
 26         du[i]=0;
 27     }
 28 }
 29 
 30 int main()
 31 {
 32     T=read();
 33     while (T--)
 34     {
 35         vector<int> g;
 36         pre=0;
 37         flag=0;
 38         n=read();
 39         m=read();
 40         init();
 41         for (int i=1;i<=m;i++)
 42         {
 43             u[i]=read();
 44             v[i]=read();
 45             int r1=Find(u[i]);
 46             int r2=Find(v[i]);
 47             if(r1!=r2)
 48             {
 49                 fa[r1]=r2;
 50                 g.push_back(1);
 51             }
 52             else
 53             {
 54                 // flag+=(++du[u[i]]==2);
 55                 // flag+=(++du[v[i]]==2);
 56                 if(++du[u[i]]==2)
 57                     flag++;
 58                 if(++du[v[i]]==2)
 59                     flag++;
 60                 g.push_back(0);
 61                 pre=i;
 62             }
 63         }
 64         if(flag==3)
 65         {
 66             init();
 67             fa[Find(u[pre])]=Find(v[pre]);
 68             for (int i=0;i<m;i++)
 69             {
 70                 if(g[i])
 71                 {
 72                     if(Find(u[i+1])==Find(v[i+1]))
 73                     {
 74                          g[i]=0;
 75                          break;
 76                     }
 77                     fa[Find(u[i+1])]=Find(v[i+1]);
 78                 }
 79             }
 80             g[pre-1]=1;
 81         }
 82         for (int i=0;i<g.size();i++)
 83             cout<<g[i];
 84         putchar('\n');
 85     }
 86     return 0;
 87     //Amireux_35
 88 }
 89 
 90 /*
 91 5 7
 92 
 93 1 2
 94 2 3
 95 3 4
 96 4 5
 97 5 1
 98 1 3
 99 3 5
100 */
CF 1726D

最小生成树:

1)Kruskal

贪心的思想,最小生成树肯定会尽可能的包含边权较小的边

考虑将将所有边权按从小到大排序,依次判断,若没有与之前选择的边一起构成环,则选择该边

正确性可以考虑对于边 e,若加入它后就不能变成最优的生成树 T,则 T+e 必定构成环

Luogu P3366

 1 //By:Komorebi_03
 2 #include<bits/stdc++.h>
 3 using namespace std;
 4 #define clear(a) memset(a,0,sizeof a)
 5 #define ll long long
 6 const int N = 1e6+5;
 7 int n,m,cnt,ans,e_cnt,fa[N];
 8 bool flag;
 9 struct node{
10     int u;
11     int v;
12     int w;
13 }e[N];
14 inline int read()
15 {
16     int x=0,f=1;char ch=getchar();
17     while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
18     while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
19     return x*f;
20 }
21 
22 void add(int u,int v,int w)
23 {
24     e[++e_cnt].u=u;
25     e[e_cnt].v=v;
26     e[e_cnt].w=w;
27 }
28 
29 int Find(int x)
30 {
31     if(x==fa[x])
32         return x;
33     return fa[x]=Find(fa[x]);
34 }
35 
36 bool cmp(node a,node b)
37 {
38     return a.w<b.w;
39 }
40 
41 int main()
42 {
43     n=read();
44     m=read();
45     for (int i=1;i<=m;i++)
46     {
47         int x=read();
48         int y=read();
49         int w=read();
50         add(x,y,w);
51     }
52     for (int i=1;i<=n;i++)
53         fa[i]=i;
54     sort(e+1,e+1+e_cnt,cmp);
55     for (int i=1;i<=e_cnt;i++)
56     {
57         int u=e[i].u;
58         int v=e[i].v;
59         int w=e[i].w;
60         int r1=Find(u);
61         int r2=Find(v);
62         if(r1!=r2)
63         {
64             fa[r2]=r1;
65             cnt++;
66             ans+=w;
67         }
68         if(cnt==n-1)
69         {
70             flag=true;
71             break;
72         }
73     }
74     if(flag)
75         cout<<ans;
76     else
77         puts("orz");
78     return 0;
79     //Amireux_35
80 }
kruskal

2)Prim

同样使用贪心的思想,Kruskal是加边,Prim是加点构成最小生成树 

具体的,从任意结点开始,每次选择一个距离当前已选结点最近的点,选择并重复

 最小生成树 - OI Wiki (oi-wiki.org)(严格次小/非严格次小生成树)

CF 707B

就是对于每一个仓库考虑与它有连边的非仓库的最短距离。

(为什么这么做是对的,因为除了仓库,所有点都是非仓库,那么如果最后选的点和最靠近它的仓库不是相邻的,那么必然可以在这个点与最靠近它的仓库的路径上选一个点使得答案可以更小)

然后把所有的取一个最小值,若所有仓库旁边都没有非仓库,那么输出 −1

 1 //By:Komorebi_03
 2 #include<bits/stdc++.h>
 3 using namespace std;
 4 #define clear(a) memset(a,0,sizeof a)
 5 #define ll long long
 6 const int INF = 0x3f3f3f3f;
 7 const int N = 1e6+5;
 8 int n,m,k,e_cnt,head[N];
 9 bool vis[N];
10 struct node{
11     int v;
12     int w;
13     int nxt;
14 }e[N];
15 inline int read()
16 {
17     int x=0,f=1;char ch=getchar();
18     while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
19     while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
20     return x*f;
21 }
22 
23 void add(int u,int v,int w)
24 {
25     e[++e_cnt].v=v;
26     e[e_cnt].w=w;
27     e[e_cnt].nxt=head[u];
28     head[u]=e_cnt;
29 }
30 
31 int main()
32 {
33     n=read();
34     m=read();
35     k=read();
36     for (int i=1;i<=m;i++)
37     {
38         int u=read();
39         int v=read();
40         int w=read();
41         add(u,v,w);
42         add(v,u,w);
43     }
44     for (int i=1;i<=k;i++)
45         vis[read()]=true;
46     int ans=INF;
47     for (int i=1;i<=n;i++)
48         if(vis[i])
49             for (int j=head[i];j;j=e[j].nxt)
50                 if(!vis[e[j].v])
51                     ans=min(ans,e[j].w);
52     if(ans==INF)
53         cout<<-1;
54     else
55         cout<<ans;
56     return 0;
57     //Amireux_35
58 }
CF707B

CF 1242B

  1 // Problem: CF1242B 0-1 MST
  2 // Contest: Luogu
  3 // URL: https://www.luogu.com.cn/problem/CF1242B
  4 // Memory Limit: 250 MB
  5 // Time Limit: 1000 ms
  6 // 
  7 // Powered by CP Editor (https://cpeditor.org)
  8 
  9 //By:Komorebi_03
 10 #include<bits/stdc++.h>
 11 using namespace std;
 12 #define clear(a) memset(a,0,sizeof a)
 13 #define ll long long
 14 const int N = 1e6+5;
 15 int n,m,id,cnt,ans=-1,e_cnt,Min,p[N],fa[N],siz[N],head[N];
 16 struct edge{
 17     int v;
 18     int nxt;
 19 }e[4*N];
 20 bool vis[N],k[N];
 21 inline int read()
 22 {
 23     int x=0,f=1;char ch=getchar();
 24     while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
 25     while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
 26     return x*f;
 27 }
 28 
 29 void add(int u,int v)
 30 {
 31     e[++e_cnt].v=v;
 32     e[e_cnt].nxt=head[u];
 33     head[u]=e_cnt;
 34 }
 35 
 36 int Find(int x)
 37 {
 38     if(fa[x]==x)
 39         return x;
 40     return fa[x]=Find(fa[x]);
 41 }
 42 
 43 void U(int x,int y)
 44 {
 45     int r1=Find(x);
 46     int r2=Find(y);
 47     if(r1!=r2)
 48         fa[r2]=r1;
 49 }
 50 
 51 int main()
 52 {
 53     n=read();
 54     m=read();
 55     for (int i=1;i<=m;i++)
 56     {
 57         int u=read();
 58         int v=read();
 59         add(u,v);
 60         add(v,u);
 61         siz[u]++;
 62         siz[v]++;
 63     }
 64     Min=n;
 65     for (int i=1;i<=n;i++)
 66     {
 67         if(Min>siz[i])
 68         {
 69             Min=siz[i];
 70             id=i;
 71         }
 72     }
 73     for (int i=1;i<=n;i++)
 74         fa[i]=i;
 75     for (int i=head[id];i;i=e[i].nxt)
 76         vis[e[i].v]=true;
 77     for (int i=1;i<=n;i++)
 78     {
 79         if(!vis[i])
 80         {
 81             fa[i]=id;
 82             k[i]=1;
 83         }
 84     }
 85     for (int i=1;i<=n;i++)
 86         if(!k[i])
 87             p[++cnt]=i;
 88     clear(vis);
 89     for (int i=1;i<=n;i++)
 90     {
 91         int tot=0;
 92         for (int j=head[i];j;j=e[j].nxt)
 93         {
 94             int v=e[j].v;
 95             vis[v]=true;
 96             tot+=k[v];
 97         }
 98         if(tot+cnt<n)
 99             U(i,id);
100         for (int j=1;j<=cnt;j++)
101             if(!vis[p[j]])
102                 U(i,p[j]);
103         for (int j=head[i];j;j=e[j].nxt)
104             vis[e[j].v]=0;
105     }
106     for (int i=1;i<=n;i++)
107         if(i==fa[i])
108             ans++;    
109     cout<<ans;
110     return 0;
111     //Amireux_35
112 }
CF 1242B

CF 606D

 1 // Problem: D. Lazy Student
 2 // Contest: Codeforces - Codeforces Round 335 (Div. 2)
 3 // URL: https://codeforces.com/problemset/problem/606/D
 4 // Memory Limit: 256 MB
 5 // Time Limit: 2000 ms
 6 // 
 7 // Powered by CP Editor (https://cpeditor.org)
 8 
 9 //By:Komorebi_03
10 #include<bits/stdc++.h>
11 using namespace std;
12 #define clear(a) memset(a,0,sizeof a)
13 #define ll long long
14 const int N = 1e6+5;
15 int n,m,u=2,v=3,cnt=1;
16 bool flag;
17 struct node{
18     int u;
19     int v;
20     int w;
21     int op;
22     int id;
23 }e[N];
24 inline int read()
25 {
26     int x=0,f=1;char ch=getchar();
27     while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
28     while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
29     return x*f;
30 }
31 
32 bool cmp(node a,node b)
33 {
34     if(a.w==b.w)
35         return a.op>b.op;
36     return a.w<b.w;
37 }
38 
39 bool out(node a,node b)
40 {
41     return a.id<b.id;
42 }
43 
44 int main()
45 {
46     n=read();
47     m=read();
48     for (int i=1;i<=m;i++)
49     {
50         e[i].w=read();
51         e[i].op=read();
52         e[i].id=i;
53     }
54     sort(e+1,e+1+m,cmp);
55     for (int i=1;i<=m;i++)
56     {
57         if(e[i].op)
58         {
59             e[i].u=1;
60             e[i].v=++cnt;
61         }
62         else
63         {
64             if(v>cnt)
65             {
66                 flag=true;
67                 break;
68             }
69             e[i].u=u++;
70             e[i].v=v;
71             if(u==v)
72             {
73                 v++;
74                 u=2;
75             }
76         }
77     }
78     if(flag)
79         cout<<-1;
80     else
81     {
82         sort(e+1,e+1+m,out);
83         for (int i=1;i<=m;i++)
84             cout<<e[i].u<<" "<<e[i].v<<"\n";
85     }
86     return 0;
87     //Amireux_35
88 }
CF 606D

 

下午:

最短路问题:

1)Floyd

 Floyd还有很多用处

比如:找图中最小环,任意两点最短路径数,计算一个图的传递背包(判断两点是否联通)

2)Dijkstra

单元最短路径算法,即求起点 S 到所有点的最短距离,但有一个限制是不能存在负权边

 3)SPFA

用于负权边的图求最短路径

CF 95C

两边DJ即可

第一次跑 n 次 DJ,求出所有点间的最短路

建新图后在跑一次 DJ,求出 S 点到 T 点的最短路

注意开 long long ,并且 INF 要设大一点

  1 // Problem: CF95C Volleyball
  2 // Contest: Luogu
  3 // URL: https://www.luogu.com.cn/problem/CF95C
  4 // Memory Limit: 250 MB
  5 // Time Limit: 2000 ms
  6 // 
  7 // Powered by CP Editor (https://cpeditor.org)
  8 
  9 //By:Komorebi_03
 10 #include<bits/stdc++.h>
 11 using namespace std;
 12 #define clear(a) memset(a,0,sizeof a)
 13 #define int long long
 14 const int INF = 0x7fffffffffffffff;
 15 const int N = 1e6+5;
 16 int n,m,s,t,dis[N],dist[N],cost[N];
 17 bool vis[N];
 18 vector<pair<int,int>> g[N],G[N];
 19 inline int read()
 20 {
 21     int x=0,f=1;char ch=getchar();
 22     while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
 23     while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
 24     return x*f;
 25 }
 26 
 27 void DJ1(int s)
 28 {
 29     clear(vis);
 30     for (int i=0;i<=n;i++)
 31         dis[i]=INF;
 32     dis[s]=0;
 33     priority_queue<pair<int,int>> q;
 34     q.push(make_pair(0,s));
 35     while (!q.empty())
 36     {
 37         int u=q.top().second;
 38         q.pop();
 39         if(vis[u])
 40             continue;
 41         vis[u]=true;
 42         for (int i=0;i<g[u].size();i++)
 43         {
 44             int v=g[u][i].first;
 45             if(!vis[v] && dis[v]>g[u][i].second+dis[u])
 46             {
 47                 dis[v]=g[u][i].second+dis[u];
 48                 q.push(make_pair(-dis[v],v));
 49             }
 50         }
 51     }
 52     for (int i=1;i<=n;i++)
 53         if(i!=s && dis[i]<=dist[s])
 54             G[s].push_back(make_pair(i,cost[s]));
 55 }
 56 
 57 void DJ2(int s)
 58 {
 59     clear(vis);
 60     for (int i=0;i<=n;i++)
 61         dis[i]=INF;
 62     dis[s]=0;
 63     priority_queue<pair<int,int>> q;
 64     q.push(make_pair(0,s));
 65     while (!q.empty())
 66     {
 67         int u=q.top().second;
 68         q.pop();
 69         if(vis[u])
 70             continue;
 71         vis[u]=true;
 72         for (int i=0;i<G[u].size();i++)
 73         {
 74             int v=G[u][i].first;
 75             if(!vis[v] && dis[v]>G[u][i].second+dis[u])
 76             {
 77                 dis[v]=G[u][i].second+dis[u];
 78                 q.push(make_pair(-dis[v],v));
 79             }
 80         }
 81     }
 82 }
 83 
 84 signed main()
 85 {
 86     n=read();
 87     m=read();
 88     s=read();
 89     t=read();
 90     for (int i=1;i<=m;i++)
 91     {
 92         int u=read();
 93         int v=read();
 94         int w=read();
 95         g[u].push_back(make_pair(v,w));
 96         g[v].push_back(make_pair(u,w));
 97     }
 98     for (int i=1;i<=n;i++)
 99     {
100         dist[i]=read();
101         cost[i]=read();
102     }
103     for (int i=1;i<=n;i++)
104         DJ1(i);
105     DJ2(s);
106     if(dis[t]==INF)
107         cout<<-1;
108     else
109         cout<<dis[t];
110     return 0;
111     //Amireux_35
112 }
CF 95C

次短路问题:

CF 25C

Floyd

每次加边后,Floyd暴力更新所有点对最短路即可

 1 // Problem: CF25C Roads in Berland
 2 // Contest: Luogu
 3 // URL: https://www.luogu.com.cn/problem/CF25C
 4 // Memory Limit: 250 MB
 5 // Time Limit: 2000 ms
 6 // 
 7 // Powered by CP Editor (https://cpeditor.org)
 8 
 9 //By:Komorebi_03
10 #include<bits/stdc++.h>
11 using namespace std;
12 #define clear(a) memset(a,0,sizeof a)
13 #define ll long long
14 const int N = 310;
15 int n,m,K,mp[N][N];
16 inline int read()
17 {
18     int x=0,f=1;char ch=getchar();
19     while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
20     while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
21     return x*f;
22 }
23 
24 int main()
25 {
26     n=read();
27     for (int i=1;i<=n;i++)
28     {
29         mp[i][i]=0;
30         for (int j=1;j<=n;j++)
31             mp[i][j]=mp[j][i]=read();
32     }
33     K=read();
34     for (int i=1;i<=K;i++)
35     {
36         ll ans=0;
37         int a=read();
38         int b=read();
39         int c=read();
40         if(mp[a][b]>c)
41         {
42             mp[a][b]=mp[b][a]=c;
43             for (int i=1;i<=n;i++)
44             {
45                 for (int j=1;j<=n;j++)
46                 {
47                     if(i==j)
48                         continue;
49                     mp[i][j]=mp[j][i]=min(mp[i][j],mp[i][a]+mp[a][j]);
50                     mp[i][j]=mp[j][i]=min(mp[i][j],mp[i][b]+mp[b][j]);
51                 }
52             }
53         }
54         for (int i=1;i<=n;i++)
55             for (int j=i+1;j<=n;j++)
56                 ans+=mp[i][j];
57         cout<<ans<<" ";
58     }
59     return 0;
60     //Amireux_35
61 }
CF 25C

CF 938D

有点权有边权,建虚点,连接每个点,边权为每个点的点权

而对于每个城市之间路径的边权,因为要来回两次,可直接 * 2

然后跑DJ即可(因为第一遍写的SPFA貌似被卡了

 1 // Problem: CF938D Buy a Ticket
 2 // Contest: Luogu
 3 // URL: https://www.luogu.com.cn/problem/CF938D
 4 // Memory Limit: 250 MB
 5 // Time Limit: 2000 ms
 6 // 
 7 // Powered by CP Editor (https://cpeditor.org)
 8 
 9 //By:Komorebi_03
10 #include<bits/stdc++.h>
11 using namespace std;
12 #define clear(a) memset(a,0x3f,sizeof a)
13 #define int long long
14 const int INF = 0x3f3f3f33f3f3f3f;
15 const int N = 4e5+10;
16 int n,m,a[N],dis[N];
17 bool vis[N];
18 vector<pair<int,int>> g[N];
19 inline int read()
20 {
21     int x=0,f=1;char ch=getchar();
22     while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
23     while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
24     return x*f;
25 }
26 
27 void DJ(int s)
28 {
29     priority_queue<pair<int,int>> q;
30     q.push(make_pair(0,s));
31     dis[s]=0;
32     while (!q.empty())
33     {
34         int u=q.top().second;
35         q.pop();
36         if(vis[u])
37             continue;
38         vis[u]=true;
39         for (int i=0;i<g[u].size();i++)
40         {
41             int v=g[u][i].first;
42             if(dis[v]>dis[u]+g[u][i].second)
43             {
44                 dis[v]=dis[u]+g[u][i].second;
45                 q.push(make_pair(-dis[v],v));
46             }
47         }
48     }
49 }
50 
51 signed main()
52 {
53     n=read();
54     m=read();
55     for (int i=1;i<=m;i++)
56     {
57         int u=read();
58         int v=read();
59         int w=read();
60         g[u].push_back(make_pair(v,w*2));
61         g[v].push_back(make_pair(u,w*2));
62     }
63     for (int i=1;i<=n;i++)
64     {
65         a[i]=read();
66         g[0].push_back(make_pair(i,a[i]));
67         g[i].push_back(make_pair(0,a[i]));
68     }
69     clear(dis);
70     DJ(0);
71     for (int i=1;i<=n;i++)
72         cout<<dis[i]<<" ";
73     return 0;
74     //Amireux_35
75 }
CF 938D

差分约束:

CF 1450E

  1 // Problem: CF1450E Capitalism
  2 // Contest: Luogu
  3 // URL: https://www.luogu.com.cn/problem/CF1450E
  4 // Memory Limit: 250 MB
  5 // Time Limit: 1000 ms
  6 // 
  7 // Powered by CP Editor (https://cpeditor.org)
  8 
  9 //By:Komorebi_03
 10 #include<bits/stdc++.h>
 11 using namespace std;
 12 #define clear(a) memset(a,0,sizeof a)
 13 #define ll long long
 14 const int N = 300;
 15 int n,m,pos,ans=-1,a[2*N],fa[2*N],mp[N][N];
 16 inline int read()
 17 {
 18     int x=0,f=1;char ch=getchar();
 19     while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
 20     while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
 21     return x*f;
 22 }
 23 
 24 int Find(int x)
 25 {
 26     if(fa[x]==x)
 27         return x;
 28     return fa[x]=Find(fa[x]);
 29 }
 30 
 31 void U(int x,int y)
 32 {
 33     int r1=Find(x);
 34     int r2=Find(y);
 35     if(r1!=r2)
 36         fa[r2]=r1;
 37 }
 38 
 39 void init()
 40 {
 41     memset(mp,N,sizeof(mp));
 42     for (int i=1;i<=n;i++)
 43         mp[i][i]=0;
 44     for (int i=1;i<=2*n;i++)
 45         fa[i]=i;
 46 }
 47 
 48 int main()
 49 {
 50     n=read();
 51     m=read();
 52     init();
 53     for (int o=1;o<=m;o++)
 54     {
 55         int i=read();
 56         int j=read();
 57         int b=read();
 58         U(i+n,j);
 59         U(i,j+n);
 60         if(b==1)
 61         {
 62             mp[i][j]=1;
 63             mp[j][i]=-1;
 64         }
 65         else
 66             mp[i][j]=mp[j][i]=1;
 67     }
 68     for (int i=1;i<=n;i++)
 69     {
 70         if(Find(i)==Find(i+n))
 71         {
 72             cout<<"NO";
 73             exit(0);
 74         }
 75     }
 76     for (int k=1;k<=n;k++)
 77         for (int i=1;i<=n;i++)
 78             for (int j=1;j<=n;j++)
 79                 mp[i][j]=min(mp[i][j],mp[i][k]+mp[k][j]);
 80     for (int i=1;i<=n;i++)
 81     {
 82         if(mp[i][i]<0)
 83         {
 84             cout<<"NO";
 85             exit(0);
 86         }
 87         int Max=-n-1;
 88         for (int j=1;j<=n;j++)
 89             Max=max(Max,mp[i][j]);
 90         if(Max>ans)
 91         {
 92             ans=Max;
 93             pos=i;
 94         }
 95     }
 96     cout<<"YES"<<"\n";
 97     cout<<ans<<"\n";
 98     for (int i=1;i<=n;i++)
 99         cout<<mp[pos][i]<<" ";
100     return 0;
101     //Amireux_35
102 }
CF 1450E

CF 1131D

  1 // Problem: CF1131D Gourmet choice
  2 // Contest: Luogu
  3 // URL: https://www.luogu.com.cn/problem/CF1131D
  4 // Memory Limit: 250 MB
  5 // Time Limit: 2000 ms
  6 // 
  7 // Powered by CP Editor (https://cpeditor.org)
  8 
  9 //By:Komorebi_03
 10 #include<bits/stdc++.h>
 11 using namespace std;
 12 #define clear(a) memset(a,0,sizeof a)
 13 #define int long long
 14 const int N = 1e6+5;
 15 int n,m,cnt,sum,e_cnt,du[N],fa[N],dis[N],head[N];
 16 string s[N];
 17 struct edge{
 18     int v;
 19     int nxt;
 20 }e[N];
 21 queue<int> q;
 22 inline int read()
 23 {
 24     int x=0,f=1;char ch=getchar();
 25     while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
 26     while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
 27     return x*f;
 28 }
 29 
 30 void add(int u,int v)
 31 {
 32     e[++e_cnt].v=v;
 33     e[e_cnt].nxt=head[u];
 34     head[u]=e_cnt;
 35 }
 36 
 37 int Find(int x)
 38 {
 39     if(fa[x]==x)
 40         return x;
 41     return fa[x]=Find(fa[x]);
 42 }
 43 
 44 void U(int x,int y)
 45 {
 46     int r1=Find(x);
 47     int r2=Find(y);
 48     if(r1!=r2)
 49         fa[r1]=r2;
 50 }
 51 
 52 void TP()
 53 {
 54     for (int i=1;i<=n+m;i++)
 55     {
 56         if(fa[i]==i)
 57         {
 58             if(!du[i])
 59             {
 60                 dis[i]=1;
 61                 q.push(i);
 62             }
 63             ++sum;
 64         }
 65     }
 66     while (!q.empty())
 67     {
 68         int u=q.front();
 69         q.pop();
 70         ++cnt;
 71         for (int i=head[u];i;i=e[i].nxt)
 72         {
 73             int v=e[i].v;
 74             dis[v]=max(dis[v],dis[u]+1);
 75             du[v]--;
 76             if(!du[v])
 77                 q.push(v);
 78         }
 79     }
 80 }
 81 
 82 signed main()
 83 {
 84     n=read();
 85     m=read();
 86     for (int i=1;i<=n+m;i++)
 87         fa[i]=i;
 88     for (int i=1;i<=n;i++)
 89     {
 90         cin>>s[i];
 91         s[i]=' '+s[i];
 92         for (int j=1;j<=m;j++)
 93             if(s[i][j]=='=')
 94                 U(i,j+n);
 95     }
 96     for (int i=1;i<=n;i++)
 97     {
 98         for (int j=1;j<=m;j++)
 99         {
100             if(s[i][j]=='>')
101             {
102                 add(Find(j+n),Find(i));
103                 du[Find(i)]++;
104             }
105             else if(s[i][j]=='<')
106             {
107                 add(Find(i),Find(j+n));
108                 du[Find(j+n)]++;
109             }
110         }
111     }
112     TP();
113     if(cnt!=sum)
114         puts("No");
115     else
116     {
117         puts("Yes");
118         for (int i=1;i<=n;i++)
119             cout<<dis[Find(i)]<<" ";
120         putchar('\n');
121         for (int i=n+1;i<=n+m;i++)
122             cout<<dis[Find(i)]<<" ";
123     }
124     return 0;
125     //Amireux_35
126 }
CF 1131D

CF 1473E

根据题意可知,要求最短路,同时最短路上最大最小边权,建分层图跑最短路即可

 1 // Problem: CF1473E Minimum Path
 2 // Contest: Luogu
 3 // URL: https://www.luogu.com.cn/problem/CF1473E
 4 // Memory Limit: 250 MB
 5 // Time Limit: 3000 ms
 6 // 
 7 // Powered by CP Editor (https://cpeditor.org)
 8 
 9 //By:Komorebi_03
10 #include<bits/stdc++.h>
11 using namespace std;
12 #define clear(a) memset(a,0x3f,sizeof a)
13 #define int long long
14 const int N = 1e6+5;
15 int n,m,e_cnt,dis[N],head[N];
16 bool vis[N];
17 struct edge{
18     int v;
19     int w;
20     int nxt;
21 }e[N];
22 vector<pair<int,int>> g[N];
23 inline int read()
24 {
25     int x=0,f=1;char ch=getchar();
26     while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
27     while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
28     return x*f;
29 }
30 
31 void add(int u,int v,int w)
32 {
33     g[u].push_back(make_pair(v,w));
34 }
35 
36 void SPFA(int s)
37 {
38     priority_queue<pair<int,int>> q;
39     dis[s]=0;
40     vis[s]=true;
41     q.push(make_pair(0,s));
42     while (!q.empty())
43     {
44         int u=q.top().second;
45         q.pop();
46         vis[u]=false;
47         for (int i=0;i<g[u].size();i++)
48         {
49             int v=g[u][i].first;
50             if(dis[v]>dis[u]+g[u][i].second)
51             {
52                 dis[v]=dis[u]+g[u][i].second;
53                 if(!vis[v])
54                 {
55                     vis[v]=true;
56                     q.push(make_pair(-dis[v],v));
57                 }
58             }
59         }
60     }
61 }
62 
63 signed main()
64 {
65     n=read();
66     m=read();
67     for (int i=1;i<=m;i++)
68     {
69         int u=read();
70         int v=read();
71         int w=read();
72         add(u,v,w);
73         add(v,u,w);
74         add(u+n,v+n,w),add(v+n,u+n,w);
75         add(u+n*2,v+n*2,w),add(v+n*2,u+n*2,w);
76         add(u+n*3,v+n*3,w),add(v+n*3,u+n*3,w);
77         
78         add(u,v+n,w*2),add(v,u+n,w*2);
79         add(u,v+n*2,0),add(v,u+n*2,0);
80         add(u+n,v+n*3,0),add(v+n,u+n*3,0);
81         add(u+2*n,v+3*n,2*w),add(v+2*n,u+3*n,2*w);
82     }
83     clear(dis);
84     SPFA(1);
85     for(int i=2;i<=n;i++)
86         cout<<min(dis[i],dis[n*3+i])<<" ";
87     return 0;
88     //Amireux_35
89 }
CF 1473E

CF 208C

首先最短路计数

通过题目易得当警局在 1 或 n 点时,每条最短路都会经过一条安全边,所以等同于最短路计数

其他情况下,只有当 1 到警局的最短路和警局到 n 的最短路之和等于 1 到 n 的最短路,才能使最短路径经过安全边,经过的条数为两倍的 1 到警局 最短路条数乘上警局到 n 的最短路条数。

 1 // Problem: CF208C Police Station
 2 // Contest: Luogu
 3 // URL: https://www.luogu.com.cn/problem/CF208C
 4 // Memory Limit: 250 MB
 5 // Time Limit: 2000 ms
 6 // 
 7 // Powered by CP Editor (https://cpeditor.org)
 8 
 9 //By:Komorebi_03
10 #include<bits/stdc++.h>
11 using namespace std;
12 #define clear(a) memset(a,0,sizeof a)
13 #define int long long
14 const int N = 1e6+5;
15 const int M = 210;
16 int n,m,e_cnt,cnt[N],sum[M][M],dis[M][M],head[N];
17 bool vis[N];
18 struct edge{
19     int v;
20     int w;
21     int nxt;
22 }e[N];
23 inline int read()
24 {
25     int x=0,f=1;char ch=getchar();
26     while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
27     while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
28     return x*f;
29 }
30 
31 void add(int u,int v)
32 {
33     e[++e_cnt].v=v;
34     e[e_cnt].nxt=head[u];
35     head[u]=e_cnt;
36 }
37 
38 void BFS(int s)
39 {
40     clear(vis);
41     queue<int> q;
42     vis[s]=true;
43     q.push(s);
44     sum[s][s]=1;
45     while (!q.empty())
46     {
47         int u=q.front();
48         q.pop();
49         for (int i=head[u];i;i=e[i].nxt)
50         {
51             int v=e[i].v;
52             if(!vis[v])
53             {
54                 vis[v]=true;
55                 dis[s][v]=dis[s][u]+1;
56                 q.push(v);
57             }
58             if(dis[s][v]==dis[s][u]+1)
59                 sum[s][v]+=sum[s][u];
60         }
61     }
62 }
63 
64 signed main()
65 {
66     n=read();
67     m=read();
68     for (int i=1;i<=m;i++)
69     {
70         int u=read();
71         int v=read();
72         add(u,v);
73         add(v,u);
74     }
75     BFS(1);
76     BFS(n);
77     int k=sum[1][n];
78     for (int i=2;i<n;i++)
79         if(dis[1][i]+dis[n][i]==dis[1][n])
80             k=max(k,sum[1][i]*sum[n][i]*2);
81     printf("%.12lf",k*1.0/sum[1][n]);
82     return 0;
83     //Amireux_35
84 }
CF 208C

扩展

prufer序列

对于这样一棵树:

初始叶结点最小为 1 号,因此对应的prufer序列先是 2 

然后叶结点 4 号对应的prufer序列是 2

依次可得 5 号对应 3,6 号对应 3,3 号对应 2,7 号对应 2;

最后这棵树的prufer序列为 223322

 Prüfer 序列 - OI Wiki (oi-wiki.org)


 

day3:

连通性问题:

有向无环图:

有向无环图是一种特殊的图,其最大意义在于能够拓扑排序。

 拓扑排序:

考虑维护一个入度为 0 的点的集合

因为这些点之间没有依赖关系,我们可以将它放在序列的开头,所有依赖关系,我们可以将它放在序列的开头,所有依赖它的点都在它后面

放在开头后删掉它,更新剩余入度为 0 的点,继续这个过程

CF 1572A

  1 // Problem: CF1572A Book
  2 // Contest: Luogu
  3 // URL: https://www.luogu.com.cn/problem/CF1572A
  4 // Memory Limit: 250 MB
  5 // Time Limit: 1500 ms
  6 // 
  7 // Powered by CP Editor (https://cpeditor.org)
  8 
  9 //By:Komorebi_03
 10 #include<bits/stdc++.h>
 11 using namespace std;
 12 #define clear(a) memset(a,0,sizeof a)
 13 #define ll long long
 14 const int N = 2e5+5;
 15 int T,n,k,ans,e_cnt,du[N],dis[N],head[N];
 16 struct edge{
 17     int v;
 18     int nxt;
 19 }e[N];
 20 inline int read()
 21 {
 22     int x=0,f=1;char ch=getchar();
 23     while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
 24     while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
 25     return x*f;
 26 }
 27 
 28 void add(int u,int v)
 29 {
 30     e[++e_cnt].v=v;
 31     e[e_cnt].nxt=head[u];
 32     head[u]=e_cnt;
 33 }
 34 
 35 queue<int> q;
 36 void TP()
 37 {
 38     for (int i=1;i<=n;i++)
 39     {
 40         if(!du[i])
 41         {
 42             q.push(i);
 43             dis[i]=1;
 44         }
 45     }
 46     while (!q.empty())
 47     {
 48         int u=q.front();
 49         q.pop();
 50         for (int i=head[u];i;i=e[i].nxt)
 51         {
 52             int v=e[i].v;
 53             if(u>v)
 54                 dis[v]=max(dis[v],dis[u]+1);
 55             else
 56                 dis[v]=max(dis[v],dis[u]);
 57             du[v]--;
 58             if(!du[v])
 59                 q.push(v);
 60         }
 61     }
 62     for (int i=1;i<=n;i++)
 63     {
 64         if(du[i]!=0)
 65         {
 66             ans=-1;
 67             return ;
 68         }
 69         ans=max(ans,dis[i]);
 70     }
 71 }
 72 
 73 void init()
 74 {
 75     ans=0;
 76     e_cnt=0;
 77     clear(du);
 78     clear(dis);
 79     clear(head);
 80 }
 81 
 82 int main()
 83 {
 84     T=read();
 85     while (T--)
 86     {
 87         n=read();
 88         init();
 89         for (int i=1;i<=n;i++)
 90         {
 91             k=read();
 92             for (int j=1;j<=k;j++)
 93             {
 94                 int p=read();
 95                 add(p,i);
 96                 du[i]++;
 97             }
 98         }
 99         TP();
100         cout<<ans<<"\n";
101     }
102     return 0;
103     //Amireux_35
104 }
CF 1572A

CF 510C

 1 // Problem: CF510C Fox And Names
 2 // Contest: Luogu
 3 // URL: https://www.luogu.com.cn/problem/CF510C
 4 // Memory Limit: 250 MB
 5 // Time Limit: 2000 ms
 6 // 
 7 // Powered by CP Editor (https://cpeditor.org)
 8 
 9 //By:Komorebi_03
10 #include<bits/stdc++.h>
11 using namespace std;
12 #define clear(a) memset(a,0,sizeof a)
13 #define ll long long
14 const int N = 1e6+5;
15 const int M = 110;
16 int n,cnt,e_cnt,du[N],head[N],vis[M][M];
17 char s[M][M],ans[N];
18 struct edge{
19     int v;
20     int nxt;
21 }e[N];
22 inline int read()
23 {
24     int x=0,f=1;char ch=getchar();
25     while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
26     while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
27     return x*f;
28 }
29 
30 void add(int u,int v)
31 {
32     e[++e_cnt].v=v;
33     e[e_cnt].nxt=head[u];
34     head[u]=e_cnt;
35 }
36 
37 void TP()
38 {
39     queue<int> q;
40     for (int i=1;i<=26;i++)
41         if(!du[i])
42             q.push(i);
43     while (!q.empty())
44     {
45         int u=q.front();
46         q.pop();
47         ans[++cnt]=u+'a'-1;
48         for (int i=head[u];i;i=e[i].nxt)
49         {
50             int v=e[i].v;
51             du[v]--;
52             if(!du[v])
53                 q.push(v);
54         }
55     }
56 }
57 
58 int main()
59 {
60     n=read();
61     for (int i=1;i<=n;i++)
62         scanf("%s",s[i]+1);
63     for (int i=1;i<=n;i++)
64     {
65         for (int j=i+1;j<=n;j++)
66         {
67             int len=min(strlen(s[i]+1),strlen(s[j]+1));
68             bool flag=false;
69             for (int k=1;k<=len;k++)
70             {
71                 if(s[i][k]!=s[j][k])
72                 {
73                     flag=true;
74                     int u=s[i][k]-'a'+1;
75                     int v=s[j][k]-'a'+1;
76                     if(!vis[u][v])
77                     {
78                         add(u,v);
79                         vis[u][v]++;
80                         du[v]++;
81                     }
82                     break;
83                 }
84             }
85             if(!flag && strlen(s[i]+1)>strlen(s[j]+1))
86             {
87                 puts("Impossible");
88                 exit(0);
89             }
90         }
91     }
92     TP();
93     if(cnt==26)
94         cout<<ans+1;
95     else
96     puts("Impossible");
97     return 0;
98     //Amireux_35
99 }
CF 510C

CF 1679D

看题目:最大权值最小,容易得出二分答案。

建出图后,若图中有环,答案显然成立,若没有环,则需要判断图中的最长路是否大于等于 k。

  1 // Problem: CF1679D Toss a Coin to Your Graph...
  2 // Contest: Luogu
  3 // URL: https://www.luogu.com.cn/problem/CF1679D
  4 // Memory Limit: 250 MB
  5 // Time Limit: 3000 ms
  6 // 
  7 // Powered by CP Editor (https://cpeditor.org)
  8 
  9 //By:Komorebi_03
 10 #include<bits/stdc++.h>
 11 using namespace std;
 12 // #define clear(a) memset(a,0,sizeof a)
 13 #define int long long
 14 const int N = 1e6+5;
 15 int n,m,k,cnt,sum,Max,a[N],u[N],v[N],du[N],dis[N],vis[N];
 16 vector<int> g[N];
 17 inline int read()
 18 {
 19     int x=0,f=1;char ch=getchar();
 20     while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
 21     while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
 22     return x*f;
 23 }
 24 
 25 void init()
 26 {
 27     cnt=0;
 28     sum=0;
 29     Max=-1;
 30     for (int i=1;i<=n;i++)
 31     {
 32         g[i].clear();
 33         du[i]=0;
 34         dis[i]=0;
 35         vis[i]=0;
 36     }
 37 }
 38 
 39 bool check(int x)
 40 {
 41     init();
 42     for (int i=1;i<=n;i++)
 43         if(a[i]<=x)
 44             dis[i]=1;
 45     for (int i=1;i<=m;i++)
 46     {
 47         if(a[u[i]]<=x && a[v[i]]<=x)
 48         {
 49             du[v[i]]++;
 50             g[u[i]].push_back(v[i]);
 51             vis[u[i]]=vis[v[i]]=1;
 52         }
 53     }
 54     queue<int> q;
 55     for (int i=1;i<=n;i++)
 56     {
 57         if(!du[i] && vis[i])
 58         {
 59             dis[i]=1;
 60             q.push(i);
 61             sum++;
 62         }
 63         else
 64             sum+=vis[i];
 65     }
 66     while (!q.empty())
 67     {
 68         int u=q.front();
 69         q.pop();
 70         ++cnt;
 71         for (int i=0;i<g[u].size();i++)
 72         {
 73             int v=g[u][i];
 74             du[v]--;
 75             dis[v]=max(dis[v],dis[u]+1);
 76             if(!du[v])
 77                 q.push(v);
 78         }
 79     }
 80     if(cnt!=sum)
 81         return true;
 82     for (int i=1;i<=n;i++)
 83         Max=max(Max,dis[i]);
 84     return Max>=k;
 85 }
 86 
 87 signed main()
 88 {
 89     n=read();
 90     m=read();
 91     k=read();
 92     for (int i=1;i<=n;i++)
 93         a[i]=read();
 94     for (int i=1;i<=m;i++)
 95     {
 96         u[i]=read();
 97         v[i]=read();
 98     }
 99     int l=1;
100     int r=1e9;
101     while (l<=r)
102     {
103         int mid=(l+r)>>1;
104         if(check(mid))
105             r=mid-1;
106         else
107             l=mid+1;
108     }
109     if(r==1e9)
110         cout<<-1;
111     else
112         cout<<r+1;
113     return 0;
114     //Amireux_35
115 }
CF 1679D

强连通分量:

CF 1220E

 1 // Problem: CF1220E Tourism
 2 // Contest: Luogu
 3 // URL: https://www.luogu.com.cn/problem/CF1220E
 4 // Memory Limit: 250 MB
 5 // Time Limit: 2000 ms
 6 // 
 7 // Powered by CP Editor (https://cpeditor.org)
 8 
 9 //By:Komorebi_03
10 #include<bits/stdc++.h>
11 using namespace std;
12 #define clear(a) memset(a,0,sizeof a)
13 #define int long long
14 const int N = 1e6+5;
15 int n,m,k,e_cnt=1,a[N],f[N],g[N],head[N];
16 bool vis[N];
17 struct edge{
18     int v;
19     int nxt;
20 }e[N];
21 inline int read()
22 {
23     int x=0,f=1;char ch=getchar();
24     while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
25     while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
26     return x*f;
27 }
28 
29 void add(int u,int v)
30 {
31     e[++e_cnt].v=v;
32     e[e_cnt].nxt=head[u];
33     head[u]=e_cnt;
34 }
35 
36 void DFS(int u,int now)
37 {
38     int sum=0;
39     int sum_=0;
40     bool flag=false;
41     vis[u]=true;
42     for (int i=head[u];i;i=e[i].nxt)
43     {
44         if(i==now)
45             continue;
46         int v=e[i].v;
47         if(vis[v])
48             flag=true;
49         else
50         {
51             DFS(v,i^1);
52             if(f[v]>=0)
53             {
54                 sum+=f[v];
55                 flag=true;
56                 sum_=max(sum_,g[v]-f[v]);
57             }
58             else
59                 sum_=max(sum_,g[v]);
60         }
61     }
62     if(flag)
63         f[u]=sum+a[u];
64     else
65         f[u]=-1;
66     g[u]=sum+sum_+a[u];
67 }
68 
69 signed main()
70 {
71     n=read();
72     m=read();
73     for (int i=1;i<=n;i++)
74         a[i]=read();
75     for (int i=1;i<=m;i++)
76     {
77         int u=read();
78         int v=read();
79         add(u,v);
80         add(v,u);
81     }
82     k=read();
83     DFS(k,0);
84     cout<<g[k];
85     return 0;
86     //Amireux_35
87 }
CF 1220E

CF 118E

有桥则一定无解

无桥则一定有解

注意路径输出

 1 //By:Komorebi_03
 2 #include<bits/stdc++.h>
 3 using namespace std;
 4 #define clear(a) memset(a,0,sizeof a)
 5 #define ll long long
 6 const int N = 1e6+5;
 7 int n,m,tim,cnt,e_cnt,dfn[N],low[N],head[N];
 8 bool vis[N];
 9 struct node{
10     int v;
11     int nxt;
12 }e[N];
13 struct edge{
14     int u;
15     int v;
16 };
17 int ansu[N],ansv[N];
18 inline int read()
19 {
20     int x=0,f=1;char ch=getchar();
21     while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
22     while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
23     return x*f;
24 }
25 
26 void add(int u,int v)
27 {
28     e[++e_cnt].v=v;
29     e[e_cnt].nxt=head[u];
30     head[u]=e_cnt;
31 }
32 
33 void TJ(int u,int fa)
34 {
35     low[u]=dfn[u]=++tim;
36     vis[u]=true;
37     for (int i=head[u];i;i=e[i].nxt)
38     {
39         int v=e[i].v;
40         if(v==fa)
41             continue;
42         if(!dfn[v])
43         {
44             TJ(v,u);
45             ansu[++cnt]=u;
46             ansv[cnt]=v;
47             low[u]=min(low[u],low[v]);
48         }
49         else
50         {
51             low[u]=min(low[u],dfn[v]);
52             if(dfn[v]<dfn[u])
53             {
54                 ansu[++cnt]=u;
55                 ansv[cnt]=v;
56             }
57         }
58         if(low[v]>dfn[u])
59         {
60             putchar('0');
61             exit(0);
62         }
63     }
64 }
65 
66 int main()
67 {
68     n=read();
69     m=read();
70     for (int i=1;i<=m;i++)
71     {
72         int u=read();
73         int v=read();
74         add(u,v);
75         add(v,u);
76     }
77     TJ(1,-1);
78     for (int i=1;i<=cnt;i++)
79         cout<<ansu[i]<<" "<<ansv[i]<<"\n";
80     return 0;
81     //Amireux_35
82 }
CF 118E

CF 555E

CF 427C

由题目易得,每个连通块只需要建一个检查站即可

所以首先求出强连通分量并缩点,每个强连通分量里的最小点权作为缩点后的点权,然后新的点权之和就是最小费用。

再求出每个强连通分量中点权与最小点权相同的点数,作为缩完后这个点的大小,根据乘法原理,最小花费的方案数就是缩完点后所有点的大小的乘积。

 1 // Problem: CF427C Checkposts
 2 // Contest: Luogu
 3 // URL: https://www.luogu.com.cn/problem/CF427C
 4 // Memory Limit: 250 MB
 5 // Time Limit: 2000 ms
 6 // 
 7 // Powered by CP Editor (https://cpeditor.org)
 8 
 9 //By:Komorebi_03
10 #include<bits/stdc++.h>
11 using namespace std;
12 #define clear(a) memset(a,0,sizeof a)
13 #define int long long
14 const int MOD = 1000000007;
15 const int N = 1e6+5;
16 int n,m,tim,cnt,tot,ans,ans_=1,e_cnt,a[N],siz[N],st[N],sum[N],num[N],low[N],dfn[N],head[N];
17 bool vis[N];
18 struct edge{
19     int v;
20     int nxt;
21 }e[N];
22 inline int read()
23 {
24     int x=0,f=1;char ch=getchar();
25     while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
26     while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
27     return x*f;
28 }
29 
30 void add(int u,int v)
31 {
32     e[++e_cnt].v=v;
33     e[e_cnt].nxt=head[u];
34     head[u]=e_cnt;
35 }
36 
37 void TJ(int u)
38 {
39     low[u]=dfn[u]=++tim;
40     st[++cnt]=u;
41     vis[u]=true;
42     for (int i=head[u];i;i=e[i].nxt)
43     {
44         int v=e[i].v;
45         if(!dfn[v])
46         {
47             TJ(v);
48             low[u]=min(low[u],low[v]);
49         }
50         else if(vis[v])
51             low[u]=min(low[u],dfn[v]);
52     }
53     if(dfn[u]==low[u])
54     {
55         ++tot;
56         int k=st[cnt--];
57         vis[k]=false;
58         num[k]=tot;
59         sum[tot]=a[k];
60         while (k!=u)
61         {
62             k=st[cnt--];
63             vis[k]=false;
64             num[k]=tot;
65             sum[tot]=min(sum[tot],a[k]);
66         }
67     }
68 }
69 
70 signed main()
71 {
72     n=read();
73     for (int i=1;i<=n;i++)
74         a[i]=read();
75     m=read();
76     for (int i=1;i<=m;i++)
77     {
78         int u=read();
79         int v=read();
80         add(u,v);
81     }
82     for (int i=1;i<=n;i++)
83         if(!dfn[i])
84             TJ(i);
85     for (int i=1;i<=n;i++)
86         if(a[i]==sum[num[i]])
87             siz[num[i]]++;
88     for (int i=1;i<=tot;i++)
89     {
90         ans+=sum[i];
91         ans_=(ans_*siz[i])%MOD;
92     }
93     cout<<ans<<" "<<ans_%MOD;
94     return 0;
95     //Amireux_35
96 }
CF 427C

2-SAT:

CF 1697F

CF 1475F

 1 // Problem: CF1475F Unusual Matrix
 2 // Contest: Luogu
 3 // URL: https://www.luogu.com.cn/problem/CF1475F
 4 // Memory Limit: 250 MB
 5 // Time Limit: 2000 ms
 6 // 
 7 // Powered by CP Editor (https://cpeditor.org)
 8 
 9 //By:Komorebi_03
10 #include<bits/stdc++.h>
11 using namespace std;
12 #define ll long long
13 const int N = 1100;
14 int T,n;
15 char mp1[N][N],mp2[N][N];
16 bool vis[N];
17 inline int read()
18 {
19     int x=0,f=1;char ch=getchar();
20     while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
21     while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
22     return x*f;
23 }
24 
25 int main()
26 {
27     T=read();
28     while (T--)
29     {
30         bool flag=false;
31         memset(vis,0,sizeof(vis));
32         n=read();
33         for (int i=1;i<=n;i++)
34             scanf("%s",mp1[i]+1);
35         for (int i=1;i<=n;i++)
36         {
37             scanf("%s",mp2[i]+1);
38             for (int j=1;j<=n;j++)
39                 mp1[i][j]^=mp2[i][j];
40         }
41         for (int i=1;i<=n;i++)
42             if(mp1[1][i] & 1)
43                 vis[i]=true;
44         for (int i=1;i<=n;i++)
45             for (int j=1;j<=n;j++)
46                 mp1[i][j]^=vis[j];
47         for (int i=1;i<=n;i++)
48         {
49             for (int j=2;j<=n;j++)
50             {
51                 if(mp1[i][j-1]!=mp1[i][j])
52                 {
53                     puts("NO");
54                     flag=true;
55                     break;
56                 }
57             }
58             if(flag)
59                 break;
60         }
61         if(!flag)
62             puts("YES");
63     }
64     return 0;
65     //Amireux_35
66 }
CF 1475F

线段树:

李超线段树

数学:

概率论

导数

同余

 


 

day4:

上午:

图论精题:

CF 1245D

 思路和前面一个题差不多,也是需要建虚点,对边权进行处理,然后跑最小生成树。

  1 // Problem: CF1245D Shichikuji and Power Grid
  2 // Contest: Luogu
  3 // URL: https://www.luogu.com.cn/problem/CF1245D
  4 // Memory Limit: 250 MB
  5 // Time Limit: 2000 ms
  6 // 
  7 // Powered by CP Editor (https://cpeditor.org)
  8 
  9 //By:Komorebi_03
 10 #include<bits/stdc++.h>
 11 using namespace std;
 12 #define int long long
 13 const int N = 1e6+5;
 14 int n,sum,ans,tot,e_cnt,st_cnt,u[N],v[N],x[N],y[N],c[N],k[N],st[N],fa[N];
 15 struct edge{
 16     int u;
 17     int v;
 18     int w;
 19 }e[6*N];
 20 inline int read()
 21 {
 22     int x=0,f=1;char ch=getchar();
 23     while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
 24     while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
 25     return x*f;
 26 }
 27 
 28 void add(int u,int v,int w)
 29 {
 30     e[++e_cnt].u=u;
 31     e[e_cnt].v=v;
 32     e[e_cnt].w=w;
 33 }
 34 
 35 int Find(int x)
 36 {
 37     if(fa[x]==x)
 38         return x;
 39     return fa[x]=Find(fa[x]);
 40 }
 41 
 42 bool cmp(edge a,edge b)
 43 {
 44     return a.w<b.w;
 45 }
 46 
 47 void Kru()
 48 {
 49     sort(e+1,e+1+e_cnt,cmp);
 50     for (int i=1;i<=e_cnt;i++)
 51     {
 52         int U=e[i].u;
 53         int V=e[i].v;
 54         int W=e[i].w;
 55         int r1=Find(U);
 56         int r2=Find(V);
 57         if(r1!=r2)
 58         {
 59             fa[r1]=r2;
 60             sum++;
 61             ans+=W;
 62             if(!e[i].u)
 63                 st[++st_cnt]=e[i].v;
 64             else
 65             {
 66                 u[++tot]=e[i].u;
 67                 v[tot]=e[i].v;
 68             }
 69         }
 70         if(sum==n)
 71             break;
 72     }
 73 }
 74 
 75 signed main()
 76 {
 77     n=read();
 78     for (int i=1;i<=n;i++)
 79         fa[i]=i;
 80     for (int i=1;i<=n;i++)
 81     {
 82         x[i]=read();
 83         y[i]=read();
 84     }
 85     for (int i=1;i<=n;i++)
 86     {
 87         c[i]=read();
 88         add(0,i,c[i]);
 89     }
 90     for (int i=1;i<=n;i++)
 91         k[i]=read();
 92     for (int i=1;i<=n;i++)
 93     {
 94         for (int j=1;j<=n;j++)
 95         {
 96             int C=(k[i]+k[j])*(abs(x[i]-x[j])+abs(y[i]-y[j]));
 97             add(i,j,C);
 98         }
 99     }
100     Kru();
101     cout<<ans<<"\n"<<st_cnt<<"\n";
102     for (int i=1;i<=st_cnt;i++)
103         cout<<st[i]<<" ";
104     putchar('\n');
105     cout<<tot<<"\n";
106     for (int i=1;i<=tot;i++)
107         cout<<u[i]<<" "<<v[i]<<"\n";
108     return 0;
109     //Amireux_35
110 }
CF 1245D

CF 1244D

  1 // Problem: CF1244D Paint the Tree
  2 // Contest: Luogu
  3 // URL: https://www.luogu.com.cn/problem/CF1244D
  4 // Memory Limit: 250 MB
  5 // Time Limit: 3000 ms
  6 // 
  7 // Powered by CP Editor (https://cpeditor.org)
  8 
  9 //By:Komorebi_03
 10 #include<bits/stdc++.h>
 11 using namespace std;
 12 #define int long long
 13 const int INF = 0x7fffffffffffffff;
 14 const int N = 1e6+5;
 15 int n,pos,ANS=INF,a[N],b[N],c[N],k[N],du[N],ans[N];
 16 vector<int> e[N];
 17 inline int read()
 18 {
 19     int x=0,f=1;char ch=getchar();
 20     while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
 21     while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
 22     return x*f;
 23 }
 24 
 25 void DFS(int now,int fa,int tot,int A,int B)
 26 {
 27     int v=-1;
 28     for (int i=0;i<e[now].size();i++)
 29         if(e[now][i]^fa)
 30             v=e[now][i];
 31     if(v==-1)
 32     {
 33         if((A==1 || A==2) && (B==1 || B==2))
 34         {
 35             tot+=c[now];
 36             k[now]=3;
 37         }
 38         if((A==3 || A==2) && (B==3 || B==2))
 39         {
 40             tot+=a[now];
 41             k[now]=1;
 42         }
 43         if((A==1 || A==3) && (B==1 || B==3))
 44         {
 45             tot+=b[now];
 46             k[now]=2;
 47         }
 48         if(tot<ANS)
 49         {
 50             ANS=tot;
 51             for (int i=1;i<=n;i++)
 52                 ans[i]=k[i];
 53         }
 54         return;
 55     }
 56     if(!A && !B)
 57     {
 58         k[now]=1;
 59         DFS(v,now,tot+a[now],1,0);
 60         k[now]=2;
 61         DFS(v,now,tot+b[now],2,0);
 62         k[now]=3;
 63         DFS(v,now,tot+c[now],3,0);
 64     }
 65     if(A && !B)
 66     {
 67         if(A==1)
 68         {
 69             k[now]=2;
 70             DFS(v,now,tot+b[now],A,2);
 71             k[now]=3;
 72             DFS(v,now,tot+c[now],A,3);
 73         }
 74         if(A==2)
 75         {
 76             k[now]=1;
 77             DFS(v,now,tot+a[now],A,1);
 78             k[now]=3;
 79             DFS(v,now,tot+c[now],A,3);
 80         }
 81         if(A==3)
 82         {
 83             k[now]=2;
 84             DFS(v,now,tot+b[now],A,2);
 85             k[now]=1;
 86             DFS(v,now,tot+a[now],A,1);
 87         }
 88     }
 89     if(A && B)
 90     {
 91         if((A==1 || A==2) && (B==1 || B==2))
 92         {
 93             k[now]=3;
 94             DFS(v,now,tot+c[now],B,3);
 95         }
 96         if((A==3 || A==2) && (B==3 || B==2))
 97         {
 98             k[now]=1;
 99             DFS(v,now,tot+a[now],B,1);
100         }
101         if((A==1 || A==3) && (B==1 || B==3))
102         {
103             k[now]=2;
104             DFS(v,now,tot+b[now],B,2);
105         }
106     }
107 }
108 
109 signed main()
110 {
111     n=read();
112     for (int i=1;i<=n;i++)
113         a[i]=read();
114     for (int i=1;i<=n;i++)
115         b[i]=read();
116     for (int i=1;i<=n;i++)
117         c[i]=read();
118     for (int i=1;i<=n-1;i++)
119     {
120         int u=read();
121         int v=read();
122         e[u].push_back(v);
123         e[v].push_back(u);
124         du[u]++;
125         du[v]++;
126     }
127     for (int i=1;i<=n;i++)
128     {
129         if(du[i]>2)
130         {
131             cout<<-1;
132             exit(0);
133         }
134         if(du[i]==1)
135             pos=i;
136     }
137     DFS(pos,-1,0,0,0);
138     cout<<ANS<<"\n";
139     for (int i=1;i<=n;i++)
140         cout<<ans[i]<<" ";
141     return 0;
142     //Amireux_35
143 }
CF 1244D

CF 623A

  1 // Problem: CF623A Graph and String
  2 // Contest: Luogu
  3 // URL: https://www.luogu.com.cn/problem/CF623A
  4 // Memory Limit: 250 MB
  5 // Time Limit: 2000 ms
  6 // 
  7 // Powered by CP Editor (https://cpeditor.org)
  8 
  9 //By:Komorebi_03
 10 #include<bits/stdc++.h>
 11 using namespace std;
 12 #define ll long long
 13 const int N = 1e6+5;
 14 const int M = 510;
 15 int n,m,cnt,du[N],fa[N],vis[N],mp[M][M];
 16 inline int read()
 17 {
 18     int x=0,f=1;char ch=getchar();
 19     while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
 20     while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
 21     return x*f;
 22 }
 23 
 24 int Find(int x)
 25 {
 26     if(fa[x]==x)
 27         return x;
 28     return fa[x]=Find(fa[x]);
 29 }
 30 
 31 void U(int x,int y)
 32 {
 33     int r1=Find(x);
 34     int r2=Find(y);
 35     if(r1!=r2)
 36         fa[r1]=r2;
 37 }
 38 
 39 int main()
 40 {
 41     n=read();
 42     m=read();
 43     for (int i=1;i<=n;i++)
 44     {
 45         fa[i]=i;
 46         mp[i][i]=1;
 47     }
 48     for (int i=1;i<=m;i++)
 49     {
 50         int u=read();
 51         int v=read();
 52         mp[u][v]=mp[v][u]=1;
 53         du[u]++;
 54         du[v]++;
 55     }
 56     for (int i=1;i<=n;i++)
 57     {
 58         if(du[i]==n-1)
 59             continue;
 60         for (int j=1;j<=n;j++)
 61             if(du[j]!=n-1)
 62                 if(mp[i][j])
 63                     U(i,j);
 64         int k=Find(i);
 65         if(!vis[k])
 66             vis[k]=++cnt;
 67     }
 68     if(cnt>2)
 69     {
 70         puts("No");
 71         exit(0);
 72     }
 73     for (int i=1;i<=n;i++)
 74     {
 75         if(du[i]==n-1)
 76             continue;
 77         for (int j=1;j<=n;j++)
 78         {
 79             if(Find(i)==Find(j))
 80             {
 81                 if(!mp[i][j])
 82                 {
 83                     puts("No");
 84                     exit(0);
 85                 }
 86             }
 87         }
 88     }
 89     puts("Yes");
 90     for (int i=1;i<=n;i++)
 91     {
 92         int k=Find(i);
 93         if(du[i]==n-1)
 94             putchar('b');
 95         else if(vis[k]==1)
 96             putchar('a');
 97         else if(vis[k]==2)
 98             putchar('c');
 99     }
100     return 0;
101     //Amireux_35
102 }
CF 623A

CF 580C

 1 // Problem: CF580C Kefa and Park
 2 // Contest: Luogu
 3 // URL: https://www.luogu.com.cn/problem/CF580C
 4 // Memory Limit: 250 MB
 5 // Time Limit: 2000 ms
 6 // 
 7 // Powered by CP Editor (https://cpeditor.org)
 8 
 9 //By:Komorebi_03
10 #include<bits/stdc++.h>
11 using namespace std;
12 #define ll long long
13 const int N = 1e6+5;
14 int n,m,ans,e_cnt,a[N],du[N],head[N];
15 struct edge{
16     int v;
17     int nxt;
18 }e[N];
19 inline int read()
20 {
21     int x=0,f=1;char ch=getchar();
22     while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
23     while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
24     return x*f;
25 }
26 
27 void add(int u,int v)
28 {
29     e[++e_cnt].v=v;
30     e[e_cnt].nxt=head[u];
31     head[u]=e_cnt;
32 }
33 
34 void DFS(int u,int from,int sum)
35 {
36     if(u!=1 && du[u]==1)
37     {
38         if(sum<=m)
39             ans++;
40         return ;
41     }
42     for (int i=head[u];i;i=e[i].nxt)
43     {
44         int v=e[i].v;
45         if(v==from)
46             continue;
47         if(!a[v])
48             DFS(v,u,0);
49         else if(sum<m)
50             DFS(v,u,sum+1);
51     }
52 }
53 
54 int main()
55 {
56     n=read();
57     m=read();
58     for (int i=1;i<=n;i++)
59         a[i]=read();
60     for (int i=1;i<=n-1;i++)
61     {
62         int u=read();
63         int v=read();
64         add(u,v);
65         add(v,u);
66         du[u]++;
67         du[v]++;
68     }
69     DFS(1,0,a[1]);
70     cout<<ans;
71     return 0;
72     //Amireux_35
73 }
CF 580C

CF 489D

 1 // Problem: CF489D Unbearable Controversy of Being
 2 // Contest: Luogu
 3 // URL: https://www.luogu.com.cn/problem/CF489D
 4 // Memory Limit: 250 MB
 5 // Time Limit: 1000 ms
 6 // 
 7 // Powered by CP Editor (https://cpeditor.org)
 8 
 9 //By:Komorebi_03
10 #include<bits/stdc++.h>
11 using namespace std;
12 #define ll long long
13 const int N = 1e6+5;
14 const int M = 3005;
15 int n,m,ans,mp[M][M];
16 vector<int> e[N];
17 inline int read()
18 {
19     int x=0,f=1;char ch=getchar();
20     while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
21     while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
22     return x*f;
23 }
24 
25 int main()
26 {
27     n=read();
28     m=read();
29     for (int i=1;i<=m;i++)
30     {
31         int u=read();
32         int v=read();
33         e[u].push_back(v);
34     }
35     for (int i=1;i<=n;i++)
36         for (int j=0;j<e[i].size();j++)
37             for (int k=0;k<e[e[i][j]].size();k++)
38                 if(i!=e[e[i][j]][k])
39                     mp[i][e[e[i][j]][k]]++;
40     for (int i=1;i<=n;i++)
41         for (int j=1;j<=n;j++)
42             ans+=mp[i][j]*(mp[i][j]-1)/2;
43     cout<<ans;
44     return 0;
45     //Amireux_35
46 }
CF 489D

CF 776D

 1 // Problem: CF776D The Door Problem
 2 // Contest: Luogu
 3 // URL: https://www.luogu.com.cn/problem/CF776D
 4 // Memory Limit: 250 MB
 5 // Time Limit: 2000 ms
 6 // 
 7 // Powered by CP Editor (https://cpeditor.org)
 8 
 9 //By:Komorebi_03
10 #include<bits/stdc++.h>
11 using namespace std;
12 #define ll long long
13 const int N = 1e6+5;
14 int n,m,a[N],fa[N],sum[N],k[3][N];
15 inline int read()
16 {
17     int x=0,f=1;char ch=getchar();
18     while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
19     while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
20     return x*f;
21 }
22 
23 int Find(int x)
24 {
25     if(fa[x]==x)
26         return x;
27     return fa[x]=Find(fa[x]);
28 }
29 
30 void U(int x,int y)
31 {
32     int r1=Find(x);
33     int r2=Find(y);
34     if(r1!=r2)
35         fa[r1]=r2;
36 }
37 
38 int main()
39 {
40     n=read();
41     m=read();
42     for (int i=1;i<=n;i++)
43         a[i]=read();
44     for (int i=1;i<=m;i++)
45     {
46         fa[i]=i;
47         fa[i+m]=i+m;
48     }
49     for (int i=1;i<=m;i++)
50     {
51         int x=read();
52         while (x--)
53         {
54             int y=read();
55             k[sum[y]++][y]=i;
56         }
57     }
58     for (int i=1;i<=n;i++)
59     {
60         if(!a[i])
61         {
62             U(k[0][i],k[1][i]+m);
63             U(k[1][i],k[0][i]+m);
64         }
65         else
66         {
67             U(k[0][i],k[1][i]);
68             U(k[0][i]+m,k[1][i]+m);
69         }
70     }
71     for (int i=1;i<=m;i++)
72     {
73         if(Find(i)==Find(i+m))
74         {
75             puts("NO");
76             exit(0);
77         }
78     }
79     puts("YES");
80     return 0;
81     //Amireux_35
82 }
CF 776D

CF 767C

 1 //By:Komorebi_03
 2 #include<bits/stdc++.h>
 3 using namespace std;
 4 #define clear(a) memset(a,0,sizeof a)
 5 #define ll long long
 6 const int N = 2e6+5;
 7 int n,cnt,sum,root,e_cnt,t[N],ans[3],num[N],head[N];
 8 struct node{
 9     int v;
10     int nxt;
11 }e[N];
12 inline int read()
13 {
14     int x=0,f=1;char ch=getchar();
15     while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
16     while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
17     return x*f;
18 }
19 
20 void add(int u,int v)
21 {
22     e[++e_cnt].v=v;
23     e[e_cnt].nxt=head[u];
24     head[u]=e_cnt;
25 }
26 
27 void DFS(int u,int from)
28 {
29     num[u]=t[u];
30     for (int i=head[u];i;i=e[i].nxt)
31     {
32         int v=e[i].v;
33         if(v==from)
34             continue;
35         DFS(v,u);
36         num[u]+=num[v];
37     }
38     if(num[u]==sum)
39     {
40         ans[++cnt]=u;
41         num[u]=0;
42     }
43 }
44 
45 int main()
46 {
47     n=read();
48     for (int i=1;i<=n;i++)
49     {
50         int a=read();
51         t[i]=read();
52         if(a)
53         {
54             add(a,i);
55             add(i,a);
56         }
57         else
58             root=i;
59         sum+=t[i];
60     }
61     if(sum%3)
62     {
63         cout<<-1;
64         exit(0);
65     }
66     sum/=3;
67     DFS(root,0);
68     if(cnt<=2)
69         cout<<-1;
70     else
71         cout<<ans[1]<<" "<<ans[2];
72     return 0;
73     //Amireux_35
74 }
CF 767C

CF 472D

 

线性代数

 

下午:

NOIP历年真题:

P7113 [NOIP2020] 排水系统

 题面非常复杂(简直可以说ex,简化为:给出一个DAG,1 ~ m为源点,出度为零的点是汇点,每个源点流量为1,过程中每个节点的流量均等的流向所有的出路。求每个汇点的流量。

依据题意建图:

 但是这题还需要高精,已经忘记高精怎么写了,所以这里用了__int128(不是懒

  1 // Problem: P7113 [NOIP2020] 排水系统
  2 // Contest: Luogu
  3 // URL: https://www.luogu.com.cn/problem/P7113
  4 // Memory Limit: 512 MB
  5 // Time Limit: 1000 ms
  6 // 
  7 // Powered by CP Edixr (https://cpedixr.org)
  8 
  9 //By:Komorebi_03
 10 #include<bits/stdc++.h>
 11 using namespace std;
 12 #define clear(a) memset(a,0,sizeof a)
 13 #define ll __int128
 14 const int N = 1e6+5;
 15 int n,m,sum,e_cnt,d[N],in[N],num[N],head[N];
 16 struct edge{
 17     int v;
 18     int nxt;
 19 }e[N];
 20 struct node{
 21     ll fz;
 22     ll fm;
 23 }k[N];
 24 queue<int> q;
 25 inline int read()
 26 {
 27     int x=0,f=1;char ch=getchar();
 28     while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
 29     while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
 30     return x*f;
 31 }
 32 
 33 void write(ll x)
 34 {
 35     if(x/10)
 36     write(x/10);
 37     putchar(x%10+'0');
 38 }
 39 
 40 void add(int u,int v)
 41 {
 42     e[++e_cnt].v=v;
 43     e[e_cnt].nxt=head[u];
 44     head[u]=e_cnt;
 45 }
 46 
 47 ll gcd(ll x,ll y)
 48 {
 49     if(y==0)
 50         return x;
 51     else
 52         return gcd(y,x%y);
 53 }
 54 
 55 void yf(int p)
 56 {
 57     ll tmp=gcd(k[p].fz,k[p].fm);
 58     k[p].fz/=tmp;
 59     k[p].fm/=tmp;
 60 }
 61 
 62 void clac(int x,int now)
 63 {
 64     ll kkk=k[x].fm*k[now].fm/(gcd(k[x].fm,k[now].fm));
 65     k[x].fz=k[x].fz*(kkk/k[x].fm);
 66     k[now].fz=k[now].fz*(kkk/k[now].fm);
 67     k[x].fz=k[x].fz+k[now].fz;
 68     k[x].fm=k[now].fm=kkk;
 69     if(k[x].fz)
 70         yf(x);
 71 }
 72 
 73 void TP()
 74 {
 75     while (!q.empty())
 76     {
 77         int u=q.front();
 78         bool flag=false;
 79         q.pop();
 80         if(d[u])
 81             k[u].fm*=d[u];
 82         if(k[u].fz)
 83             yf(u);
 84         for (int i=head[u];i;i=e[i].nxt)
 85         {
 86             flag=true;
 87             int v=e[i].v;
 88             in[v]--;
 89             clac(v,u);
 90             if(!in[v])
 91                 q.push(v);
 92         }
 93         if(flag)
 94         {
 95             k[u].fz=0;
 96             k[u].fm=1;
 97         }
 98     }
 99 }
100 
101 int main()
102 {
103     n=read();
104     m=read();
105     for (int i=1;i<=n;i++)
106     {
107         k[i].fz=0;
108         k[i].fm=1;
109         d[i]=read();
110         if(!d[i])
111             num[++sum]=i;
112         for (int j=1;j<=d[i];j++)
113         {
114             int a=read();
115             add(i,a);
116             in[a]++;
117         }
118     }
119     for (int i=1;i<=n;i++)
120     {
121         if(!in[i])
122         {
123             k[i].fz=k[i].fm=1;
124             q.push(i);
125         }
126     }
127     TP();
128     for (int i=1;i<=sum;i++)
129     {
130         yf(num[i]);
131         write(k[num[i]].fz);
132         putchar(' ');
133         write(k[num[i]].fm);
134         putchar('\n');
135     }
136     return 0;
137     //Amireux_35
138 }
P7113 [NOIP2020] 排水系统

P1525 [NOIP2010 提高组] 关押罪犯

并查集

首先从大到小排序

然后再结合敌人的敌人和自己在一个监狱的规律合并

当查找时发现其中两个罪犯不可避免地碰撞到一起时 只能将其输出并结束

 1 //By:Komorebi_03
 2 #include<bits/stdc++.h>
 3 using namespace std;
 4 #define ll long long
 5 const int N = 1e6+5;
 6 int n,m,fa[N],vis[N];
 7 struct node{
 8     int u;
 9     int v;
10     int w;
11 }a[N];
12 inline int read()
13 {
14     int x=0,f=1;char ch=getchar();
15     while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
16     while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
17     return x*f;
18 }
19 
20 bool cmp(node x,node y)
21 {
22     return x.w>y.w;
23 }
24 
25 int Find(int x)
26 {
27     if(fa[x]==x)
28         return x;
29     return fa[x]=Find(fa[x]);
30 }
31 
32 void U(int x,int y)
33 {
34     int s1=Find(x);
35     int s2=Find(y);
36     if(s1!=s2)
37         fa[s1]=s2;
38 }
39 
40 bool check(int x,int y)
41 {
42     int t1=Find(x);
43     int t2=Find(y);
44     if(t1==t2)
45         return true;
46     return false;
47 }
48 
49 int main()
50 {
51     n=read();
52     m=read();
53     for (int i=1;i<=n;i++)
54         fa[i]=i;
55     for (int i=1;i<=m;i++)
56     {
57         a[i].u=read();
58         a[i].v=read();
59         a[i].w=read();
60     }
61     sort(a+1,a+1+m,cmp);
62     for (int i=1;i<=m;i++)
63     {
64         int u=a[i].u;
65         int v=a[i].v;
66         int w=a[i].w;
67         if(check(u,v))
68         {
69             cout<<w;
70             exit(0);
71         }
72         if(!vis[u])
73             vis[u]=v;
74         else
75             U(vis[u],v);
76         if(!vis[v])
77             vis[v]=u;
78         else
79             U(vis[v],u);
80     }
81     cout<<0;
82     return 0;
83     //Amireux_35
84 }
P1525 [NOIP2010 提高组] 关押罪犯

P1983 [NOIP2013 普及组] 车站分级

 1 //By:Komorebi_03
 2 #include<bits/stdc++.h>
 3 using namespace std;
 4 #define ll long long
 5 const int N = 1e6;
 6 const int M = 1e3+5;
 7 int n,m,ans,e_cnt,a[N],k[N],in[N],head[N],vis[M][M];
 8 struct node{
 9     int v;
10     int nxt;
11 }e[N];
12 inline int read()
13 {
14     int x=0,f=1;char ch=getchar();
15     while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
16     while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
17     return x*f;
18 }
19 
20 void add(int u,int v)
21 {
22     e[++e_cnt].v=v;
23     e[e_cnt].nxt=head[u];
24     head[u]=e_cnt;
25 }
26 
27 void TP()
28 {
29     queue<pair<int,int>> q;
30     for (int i=1;i<=n;i++)
31         if(!in[i])
32             q.push(make_pair(i,1));
33     while (!q.empty())
34     {
35         int now=q.front().first;
36         int dep=q.front().second;
37         q.pop();
38         if(dep>ans)
39             ans=dep;
40         for (int i=head[now];i;i=e[i].nxt)
41         {
42             int v=e[i].v;
43             in[v]--;
44             if(in[v]==0)
45                 q.push(make_pair(v,dep+1));
46         }
47     }
48 }
49 
50 int main()
51 {
52     n=read();
53     m=read();
54     while (m--)
55     {
56         memset(k,0,sizeof(k));
57         int s=read();
58         for (int i=1;i<=s;i++)
59         {
60             scanf("%d",a+i);
61             k[a[i]]=1;
62         }
63         for (int i=a[1];i<=a[s];i++)
64         {
65             if(!k[i])
66             {
67                 for (int j=1;j<=s;j++)
68                 {
69                     if(!vis[a[j]][i])
70                     {
71                         add(a[j],i);
72                         vis[a[j]][i]=1;
73                         in[i]++;
74                     }
75                 }
76             }
77         }
78     }
79     TP();
80     cout<<ans;
81     return 0;
82 }
P1983 [NOIP2013 普及组] 车站分级

P2296 [NOIP2014 提高组] 寻找道路

  1 //By:Komorebi_03
  2 #include<bits/stdc++.h>
  3 using namespace std;
  4 #define ll long long
  5 const int INF = 0x3f3f3f;
  6 const int N = 1e6+5;
  7 int n,m,s,t,e_cnt,dis[N],head[N];
  8 bool vis[N],vis_[N];
  9 struct edge{
 10     int v;
 11     int nxt;
 12 }e[N];
 13 inline int read()
 14 {
 15     int x=0,f=1;char ch=getchar();
 16     while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
 17     while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
 18     return x*f;
 19 }
 20 
 21 void add(int u,int v)
 22 {
 23     e[++e_cnt].v=v;
 24     e[e_cnt].nxt=head[u];
 25     head[u]=e_cnt;
 26 }
 27 
 28 void bfs(int t)
 29 {
 30     memset(vis,false,sizeof(vis));
 31     queue<int> q;
 32     q.push(t);
 33     vis[t]=vis_[t]=true;
 34     while (!q.empty())
 35     {
 36         int u=q.front();
 37         q.pop();
 38         for (int i=head[u];i;i=e[i].nxt)
 39         {
 40             int v=e[i].v;
 41             if(!vis[v])
 42             {
 43                 vis[v]=true;
 44                 vis_[v]=true;
 45                 q.push(v);
 46             }
 47         }
 48     }
 49 }
 50 
 51 void SPFA(int t)
 52 {
 53     memset(vis,false,sizeof(vis));
 54     memset(dis,INF,sizeof(dis));
 55     queue<int> q;
 56     q.push(t);
 57     vis[t]=true;
 58     dis[t]=0;
 59     while (!q.empty())
 60     {
 61         int u=q.front();
 62         q.pop();
 63         vis[u]=false;
 64         for (int i=head[u];i;i=e[i].nxt)
 65         {
 66             int v=e[i].v;
 67             if(dis[v]>dis[u]+1 && vis_[v])
 68             {
 69                 dis[v]=dis[u]+1;
 70                 if(!vis[v])
 71                 {
 72                     vis[v]=true;
 73                     q.push(v);
 74                 }
 75             }
 76         }
 77     }
 78 }
 79 
 80 int main()
 81 {
 82     n=read();
 83     m=read();
 84     for (int i=1;i<=m;i++)
 85     {
 86         int u=read();
 87         int v=read();
 88         add(v,u);
 89     }
 90     s=read();
 91     t=read();
 92     bfs(t);
 93     for (int i=1;i<=n;i++)
 94     {
 95         if(!vis[i])
 96             for (int j=head[i];j;j=e[j].nxt)
 97                 if(vis_[e[j].v])
 98                     vis_[e[j].v]=false;
 99     }
100     SPFA(t);
101     if(dis[s]>=INF)
102         cout<<-1;
103     else
104         cout<<dis[s];
105     return 0;
106     //Amireux_35
107 }
P2296 [NOIP2014 提高组] 寻找道路

P1967 [NOIP2013 提高组] 货车运输

  1 //By:Komorebi_03
  2 #include<bits/stdc++.h>
  3 using namespace std;
  4 #define ll long long
  5 const int INF = 0x3f3f3f3f;
  6 const int N = 1e6+5;
  7 const int M= 1e2;
  8 int n,m,cnt,fa[N],vis[N],dep[N],head[N],f[N][M],w[N][M];
  9 struct edge{
 10     int x;
 11     int y;
 12     int dis;
 13 }E[N];
 14 struct node{
 15     int v;
 16     int w;
 17     int nxt;
 18 }e[N];
 19 inline int read()
 20 {
 21     int x=0,f=1;char ch=getchar();
 22     while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
 23     while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
 24     return x*f;
 25 }
 26 
 27 void addedge(int u,int v,int w)
 28 {
 29     e[++cnt].v=v;
 30     e[cnt].w=w;
 31     e[cnt].nxt=head[u];
 32     head[u]=cnt;
 33 }
 34 
 35 bool cmp(edge a,edge b)
 36 {
 37     return a.dis>b.dis;
 38 }
 39 
 40 int Find(int x)
 41 {
 42     if(fa[x]==x)
 43         return x;
 44     return fa[x]=Find(fa[x]);
 45 }
 46 
 47 void Kru()
 48 {
 49     sort(E+1,E+1+m,cmp);
 50     for (int i=1;i<=n;i++)
 51         fa[i]=i;
 52     for (int i=1;i<=m;i++)
 53     {
 54         int s1=Find(E[i].x);
 55         int s2=Find(E[i].y);
 56         if(s1^s2)
 57         {
 58             fa[s2]=s1;
 59             addedge(E[i].x,E[i].y,E[i].dis);
 60             addedge(E[i].y,E[i].x,E[i].dis);
 61         }
 62     }
 63     return ;
 64 }
 65 
 66 void dfs(int k)
 67 {
 68     vis[k]=1;
 69     for (int i=head[k];i;i=e[i].nxt)
 70     {
 71         int v=e[i].v;
 72         if(vis[v])
 73             continue;
 74         dep[v]=dep[k]+1;
 75         f[v][0]=k;
 76         w[v][0]=e[i].w;
 77         dfs(v);
 78     }
 79     return ;
 80 }
 81 
 82 int LCA(int x,int y)
 83 {
 84     if(Find(x)^Find(y))
 85         return -1;
 86     int ans=INF;
 87     if(dep[x]>dep[y])
 88         swap(x,y);
 89     for (int i=20;i>=0;i--)
 90     {
 91         if(dep[f[y][i]]>=dep[x])
 92         {
 93             ans=min(ans,w[y][i]);
 94             y=f[y][i];
 95         }
 96     }
 97     if(x==y)
 98         return ans;
 99     for (int i=20;i>=0;i--)
100     {
101         if(f[x][i]^f[y][i])
102         {
103             ans=min(ans,min(w[x][i],w[y][i]));
104             x=f[x][i];
105             y=f[y][i];
106         }
107     }
108     ans=min(ans,min(w[x][0],w[y][0]));
109     return ans;
110 }
111 
112 int main()
113 {
114     n=read();
115     m=read();
116     for (int i=1;i<=m;i++)
117     {
118         int x=read();
119         int y=read();
120         int z=read();
121         E[i].x=x;
122         E[i].y=y;
123         E[i].dis=z;
124     }
125     Kru();
126     for (int i=1;i<=n;i++)
127     {
128         if(!vis[i])
129         {
130             dep[i]=1;
131             dfs(i);
132             f[i][0]=i;
133             w[i][0]=INF;
134         }
135     }
136     for (int i=1;i<=20;i++)
137     {
138         for (int j=1;j<=n;j++)
139         {
140             f[j][i]=f[f[j][i-1]][i-1];
141             w[j][i]=min(w[j][i-1],w[f[j][i-1]][i-1]);
142         }
143     }
144     int q=read();
145     for (int i=1;i<=q;i++)
146     {
147         int x=read();
148         int y=read();
149         cout<<LCA(x,y)<<"\n";
150     }
151     return 0;
152 }
P1967 [NOIP2013 提高组] 货车运输

P2661 [NOIP2015 提高组] 信息传递

 1 //By:Komorebi_03
 2 #include<bits/stdc++.h>
 3 using namespace std;
 4 #define clear(a) memset(a,0,sizeof a)
 5 #define ll long long
 6 const int N = 1e6+5;
 7 int n,Min=0x3f3f3f,t[N],f[N],dis[N];
 8 inline int read()
 9 {
10     int x=0,f=1;char ch=getchar();
11     while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
12     while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
13     return x*f;
14 }
15 
16 int Find(int x)
17 {
18     if(f[x]!=x)
19     {
20         int root=f[x];
21         f[x]=Find(f[x]);
22         dis[x]+=dis[root];
23     }
24     return f[x];
25 }
26 
27 int main()
28 {
29     n=read();
30     for (int i=1;i<=n;i++)
31         f[i]=i;
32     for (int i=1;i<=n;i++)
33     {
34         t[i]=read();
35         int r1=Find(i);
36         int r2=Find(t[i]);
37         if(r1!=r2)
38         {
39             f[r1]=r2;
40             dis[i]=dis[t[i]]+1;    
41         }
42         else
43             Min=min(Min,dis[i]+dis[t[i]]+1);
44     }
45     cout<<Min;
46     return 0;
47     //Amireux_35
48 }
P2661 [NOIP2015 提高组] 信息传递

P2680 [NOIP2015 提高组] 运输计划

 

 

 


 

五一题单

posted @ 2023-04-30 21:19  Komorebi_03  阅读(65)  评论(2编辑  收藏  举报