20241221北京总结
授课内容:图论 , 网络流
我在网络流方面相当缺失 , 回去之后要先补一补
图论很难说有一些具体算法,主要是思想,trick 之类的,多见见题就好了
今天主要了解差分约束 , 同余最短路 , 联通性问题(强连通分量 , 边双 , 点双 )
P3275 [SCOI2011] 糖果
差分约束板子 , 但直接跑会 \(T\) , 所以把零环缩一下点就行
#include<bits/stdc++.h>
using namespace std;
struct edge{
int nxt,to,len;
}e[1100000];
int head[1100000],cnt;
long long n,k,ans;
int dis[1100000];
int use[1100000];
bool vis[1100000];
void add(int x,int y,int len){
e[++cnt].to=y;
e[cnt].nxt=head[x];
e[cnt].len=len;
head[x]=cnt;
}
queue<int> q;
int main(){
cin>>n>>k;
for(int i=1;i<=k;i++){
int x,a,b;
cin>>x>>a>>b;
if(x==1){
add(a,b,0);
add(b,a,0);
}
if(x==2){
add(a,b,1);
}
if(x==3){
add(b,a,0);
}
if(x==4){
add(b,a,1);
}
if(x==5){
add(a,b,0);
}
}
for(int i=1;i<=n;i++) {
vis[i]=true;
dis[i]=1;
use[i]=1;
q.push(i);
}
int tot=0;
while(!q.empty()){
tot++;
if(tot>2e7){
cout<<-1<<'\n';
return 0;
}
int now=q.front();
q.pop();
vis[now]=false;
use[now]=0;
for(int i=head[now];i;i=e[i].nxt){
int to=e[i].to;
if(dis[to]<dis[now]+e[i].len){
use[i]++;
if(use[i]==n-1){
cout<<-1<<'\n';
return 0;
}
dis[to]=dis[now]+e[i].len;
if(!vis[to]){
q.push(to);
vis[to]=1;
}
}
}
}
for(int i=1;i<=n;i++){
ans=ans+dis[i];
}
cout<<ans;
return 0;
}
CF19EFairy
就是删奇环 , 考虑到 \(dfs\) 树环都是返祖边的优良性质 , 就直接先把 \(dfs\) 树跑出来 , 找到返祖边上的奇环 .
由于环的可加性 , 我们这条边在过所有奇环的同时一个偶环也过不了 , 于是就考虑树上差分 , 通过链上加减来维护
/*
* @Author: 2019yyy
* @Date: 2024-12-21 08:13:23
* @LastEditors: 2019yyy
* @LastEditTime: 2024-12-21 16:35:37
* @FilePath: \code\20241221\CF19E.cpp
* @Description:
*
* I love Chtholly forever
*/
#include<bits/stdc++.h>
using namespace std;
struct Edge{
int next,to;
} a[1100000];
int cnt=1,head[11000000];
void addEdge(int x,int y){
a[++cnt].next=head[x];
a[cnt].to=y;
head[x]=cnt;
}
int fa[1100000][21];
int f[1100000],dep[1100000],id[1100000];
void dfs(int x,int father){
for(int i=head[x];i;i=a[i].next){
int to=a[i].to;
if(to==father or dep[to]){
continue;
}
fa[to][0]=x;
dep[to]=dep[x]+1;
id[to]=i/2;
dfs(to,x);
}
}
int anscnt=0;
int lca(int x,int y){
if(dep[x]!=dep[y]){
if(dep[y]>dep[x]){
swap(x,y);
}
for(int i=20;i>=0;i--){
if(dep[fa[x][i]]>=dep[y]){
x=fa[x][i];
}
}
}
if(x==y){
return x;
}
for(int i=20;i>=0;i--){
if(fa[x][i]!=fa[y][i]){
x=fa[x][i];
y=fa[y][i];
}
}
return fa[x][0];
}
bool vis[1100000];
int h[1100000];
void dfs1(int x,int father){
vis[x]=true;
for(int i=head[x];i;i=a[i].next){
int to=a[i].to;
if((i xor 1)==father){
continue;
}
if(vis[to]){
if(dep[x]<=dep[to]){
continue;
}
if((dep[x]-dep[to]) bitand 1){
f[x]-=1;
f[to]-=1;
h[i/2]--;
f[lca(x,to)]+=2;
}else{
f[x]+=1;
f[to]+=1;
h[i/2]++;
f[lca(x,to)]-=2;
anscnt++;
}
}else{
dfs1(to,i);
}
}
}
bool vis2[1100000],flag;
int g[1100000],ans,res[1100000];
void dfs2(int x,int father){
vis2[x]=true;
g[x]=f[x];
for(int i=head[x];i;i=a[i].next){
int to=a[i].to;
if((i xor 1)==father){
continue;
}
if(vis2[to]){
if(dep[x]<=dep[to]){
continue;
}
if(h[i/2]==anscnt){
res[++ans]=i/2;
}
continue;
}
dfs2(to,father);
g[x]+=g[to];
}
if(g[x]==anscnt){
if(id[x]!=0){
res[++ans]=id[x];
}
}
}
int main(){
int n,m;
cin>>n>>m;
for(int i=1;i<=m;i++){
int x,y;
cin>>x>>y;
addEdge(x,y);
addEdge(y,x);
}
for(int i=1;i<=n;i++){
if(not dep[i]){
dep[i]=1;
dfs(i,0);
}
}
for(int j=1;j<=20;j++){
for(int i=1;i<=n;i++){
fa[i][j]=fa[fa[i][j-1]][j-1];
}
}
int t=0;
for(int i=1;i<=n;i++){
if(not vis[i]){
anscnt=0,flag=false;
dfs1(i,-1);
t=t+anscnt;
if(anscnt!=0){
dfs2(i,-1);
}
}
}
if(t==0){
cout<<m<<'\n';
for(int i=1;i<=m;i++){
cout<<i<<" ";
}
return 0;
}
sort(res+1,res+ans+1);
ans=unique(res+1,res+ans+1)-(res+1);
cout<<ans<<'\n';
for(int i=1;i<=ans;i++){
cout<<res[i]<<' ';
}
return 0;
}
CF412DGiving Awards
简单考虑一下顺序发现是后续遍历 , 简单切掉
#include<bits/stdc++.h>
using namespace std;
struct addEdge{
int next,to;
} a[1100000];
int head[1100000],cnt;
void addEdge(int x,int y){
a[++cnt].to=y;
a[cnt].next=head[x];
head[x]=cnt;
}
bool vis[1100000];
void dfs(int x){
vis[x]=true;
for(int i=head[x];i;i=a[i].next){
int to=a[i].to;
if(vis[to]){
continue;
}
dfs(to);
}
cout<<x<<" ";
}
int main(){
int n,m;
cin>>n>>m;
for(int i=1;i<=m;i++){
int x,y;
cin>>x>>y;
addEdge(x,y);
}
for(int i=1;i<=n;i++){
if(not vis[i]){
dfs(i);
}
}
cout<<'\n';
return 0;
}
P7428 [THUPC2017] 母亲节的礼物
不太好做 , 贺了一下题解发现一定有解 , 所以直接上随机化
先随机一个颜色 , 再处理所有不合法的 (放到一个队列里) , 然后处理不合法的 , 把不合法的改变一下颜色
/*
* @Author: 2019yyy
* @Date: 2024-12-21 21:14:14
* @LastEditors: 2019yyy
* @LastEditTime: 2024-12-21 22:00:54
* @FilePath: \code\20241221\P7428.cpp
* @Description:
*
* I love Chtholly forever
*/
#include<bits/stdc++.h>
using namespace std;
struct addEdge{
int next,to;
} a[1100000];
int head[1100000],cnt;
void addEdge(int x,int y){
a[++cnt].to=y;
a[cnt].next=head[x];
head[x]=cnt;
}
int col[1100000];
int fun(int x,int co){
int res=0;
for(int i=head[x];i;i=a[i].next){
if(co==col[a[i].to]){++res;}
}
return res;
}
queue<int> q;
int main(){
srand(time(0));
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int T;
cin>>T;
while(T--){
memset(head,0,sizeof(head));
int n,m;
cin>>n>>m;
cnt=0;
for(int i=1;i<=m;i++){
int x,y;
cin>>x>>y;
addEdge(x,y);
addEdge(y,x);
}
while(!q.empty()){
q.pop();
}
for(int i=1;i<=n;i++){
col[i]=rand()%4;
if(fun(i,col[i])>1){
q.push(i);
}
}
while(not q.empty()){
int now=q.front();
q.pop();
if(fun(now,col[now])<=1){
continue;
}
int minn=0x3f3f3f3f;
for(int i=0;i<4;++i){
int t=fun(now,i);
if(t<minn){
minn=t;
col[now]=i;
}
}
for(int i=head[now];i;i=a[i].next){
int to=a[i].to;
if(col[to]==col[now] and fun(to,col[now])>1){
q.push(to);
}
}
}
for(int i=1;i<=n;i++){
cout<<(char)('a'+col[i]);
}
cout<<'\n';
}
}
P4819 [中山市选] 杀人游戏
容易发现一个 \(SCC\) 里的所有点都能互相监督 , 进一个不是杀人犯的点就 \(win\) 了 , 所以直接缩点
完了考虑不在缩点后的 \(DAG\) 怎么做 , 简单的想 , 若是监督了一个入度为 \(0\) 的点 , 紧接着与它相链接的点就被查明了 , 所以答案只与入读为 \(0\) 的点有关
注意特判(有很多)
/*
* @Author: 2019yyy
* @Date: 2024-12-21 19:18:55
* @LastEditors: 2019yyy
* @LastEditTime: 2024-12-21 21:11:04
* @FilePath: \code\20241221\P4819.cpp
* @Description:
*
* I love Chtholly forever
*/
#include<bits/stdc++.h>
using namespace std;
struct Graph{
struct Edge{
int next,to;
} a[3100000];
int head[3100000],cnt;
void addEdge(int x,int y){
a[++cnt].to=y;
a[cnt].next=head[x];
head[x]=cnt;
}
} g,f;
int dfscnt,colcnt,dfn[3100000],low[3100000],col[3100000],deg[3100000];
vector<int> scc[3100000];
bool vis[3100000];
stack<int> s;
void Tarjan(int x,int fa){
dfn[x]=low[x]=++dfscnt;
s.push(x);vis[x]=true;
for(int i=g.head[x];i;i=g.a[i].next){
int to=g.a[i].to;
if(to==fa){
continue;
}
if(not dfn[to]){
Tarjan(to,x);
low[x]=min(low[x],low[to]);
}else{
if(vis[to]){
low[x]=min(low[x],dfn[to]);
}
}
}
if(low[x]==dfn[x]){
scc[++colcnt].push_back(x);
col[x]=colcnt;vis[x]=false;
while(not s.empty() and s.top()!=x){
int now=s.top();
scc[colcnt].push_back(now);
s.pop();col[now]=colcnt;vis[now]=false;
}
s.pop();
}
}
bool flag[1100000];
int main(){
int n,m;
cin>>n>>m;
for(int i=1;i<=m;i++){
int x,y;
cin>>x>>y;
g.addEdge(x,y);
}
if(n==1){ return cout<<"1.000000",0;}
for(int i=1;i<=n;i++){
if(not dfn[i]){
Tarjan(i,0);
}
}
for(int i=1;i<=colcnt;i++){
for(auto j:scc[i]){
for(int k=g.head[j];k;k=g.a[k].next){
int to=g.a[k].to;
if(flag[col[to]] or col[to]==i){
continue;
}
f.addEdge(i,col[to]);
deg[col[to]]++;flag[col[to]]=true;
}
}
for(int j=f.head[i];j;j=f.a[j].next){
flag[f.a[j].to]=false;
}
}
int ans=0;
bool fl=true;
for(int i=1;i<=colcnt;i++){
if(deg[i]==0){
ans++;
}
if(deg[i] or scc[i].size()>1){
continue;
}
if(fl){
bool fla=true;
for(int j=f.head[i];j;j=f.a[j].next){
if(deg[f.a[j].to]<=1){
fla=false;break;
}
}
if(fla){
ans--,fl=false;
}
}
}
if((double)(n-ans)/(double)(n)==0.8){
cout<<"0.600000\n";
return 0;
}
cout<<setprecision(6)<<fixed<<(double)(n-ans)/(double)(n)<<'\n';
return 0;
}
P2371 [国家集训队] 墨墨的等式 and P3403 跳楼机
同余最短路板子


浙公网安备 33010602011771号