CF118E Bertown roads
题意:无向连通图,给边定向,使其强连通。
题解:DFS,树边向下连,返祖边向上连,注意判断无解。
#include<bits/stdc++.h>
using namespace std;
int getint(){ int x;scanf("%d",&x);return x; }
const int N=1e5+10,M=6e5+10;
struct bian{
int l,e,n;
};
bian b[M];
int s[N],tot=1;
void add(int x,int y){
tot++;
b[tot].e=y;
b[tot].n=s[x];
s[x]=tot;
}
bool vis[N];
int nfd[N],dfnn=0;
void ss0(int x){
vis[x]=1;
for(int i=s[x];i;i=b[i].n){
if(vis[b[i].e]){ if(!b[i^1].l) b[i].l=1; continue; }
b[i].l=1;
ss0(b[i].e);
}
}
void ss1(int x){
vis[x]=1;
for(int i=s[x];i;i=b[i].n){
if(b[i].l)continue;
if(vis[b[i].e])continue;
ss1(b[i].e);
}
}
int main(){
int n=getint(),m=getint();
for(int i=0;i<m;i++){
int x=getint(),y=getint();
add(x,y);
add(y,x);
}
ss0(1);
memset(vis,0,sizeof(bool)*(n+2));
ss1(1);
bool ok=1;
for(int i=1;i<=n;i++)if(!vis[i])ok=0;
if(!ok)puts("0");
else for(int i=1;i<=n;i++)for(int j=s[i];j;j=b[j].n)if(b[j].l)printf("%d %d
",i,b[j].e);
}
CF231E Cactus
题意:给定一点仙人掌,多次询问 (u) 到 (v) 的简单路径数量。
题解:每个环会让答案 ( imes 2);于是把环缩成点,询问即在树上统计链上有多少环缩成的点。
#include<bits/stdc++.h>
using namespace std;
int getint(){ int x;scanf("%d",&x);return x; }
const int N=2e5+10,M=4e5+10;
struct bian{
int l,e,n;
};
bian b[M];
int s[N],tot=1;
void add(int x,int y){
tot++;
b[tot].e=y;
b[tot].n=s[x];
s[x]=tot;
}
int v[N];
int col[N];
namespace Graph{
bian b[M];
int s[N],tot=1;
void add(int x,int y){
tot++;
b[tot].e=y;
b[tot].n=s[x];
s[x]=tot;
}
int stk[N],top;
bool vis[N];
bool instk[N];
int cnt;
void ss(int x,int fa){
stk[top++]=x;
instk[x]=1;
vis[x]=1;
for(int i=s[x];i;i=b[i].n){
int v=b[i].e;
if(i==(fa^1))continue;
if(!vis[v])ss(v,i);
if(instk[v]){
++cnt;
while(stk[top]!=v){
--top;
col[stk[top]]=cnt;
}
::v[cnt]++;
}
}
instk[x]=0;
if(!col[x])col[x]=++cnt,--top;
// cerr<<x<<"! ";for(int i=0;i<top;i++)cerr<<" "<<stk[i];cerr<<endl;
}
} // namespace Graph
const int L=18;
int f[L][N],dep[N];
bool vis[N];
void ss(int x,int fa){
vis[x]=1;
for(int i=s[x];i;i=b[i].n){
int v=b[i].e;
if(vis[v])continue;
::v[v]+=::v[x];
dep[v]=dep[x]+1;
f[0][v]=x;
ss(b[i].e,x);
}
}
void init_lca(int n){
for(int i=1;i<L;i++)
for(int j=1;j<=n;j++)f[i][j]=f[i-1][f[i-1][j]];
}
int lca(int x,int y){
if(dep[x]<dep[y])swap(x,y);
for(int i=L-1;i>=0;i--)if(dep[f[i][x]]>=dep[y])x=f[i][x];
if(x==y)return x;
for(int i=L-1;i>=0;i--)if(f[i][x]!=f[i][y])x=f[i][x],y=f[i][y];
return f[0][x];
}
int query(int x,int y){
int l=lca(x,y);
return v[x]+v[y]-v[l]-v[f[0][l]];
}
int p2[N];
int main(){
int n=getint(),m=getint();
for(int i=0;i<m;i++){
int x=getint(),y=getint();
Graph::add(x,y);
Graph::add(y,x);
}
Graph::ss(1,0);
for(int i=1;i<=n;i++)for(int j=Graph::s[i];j;j=Graph::b[j].n)
add(col[i],col[Graph::b[j].e]),
add(col[Graph::b[j].e],col[i]);
dep[1]=1;
ss(1,0);
p2[0]=1;
for(int i=1;i<=n;i++)p2[i]=p2[i-1]*2ll%1000000007;
n=Graph::cnt;
init_lca(n);
int q=getint();
while(q--){
int x=getint(),y=getint();
printf("%d
",p2[query(col[x],col[y])]);
}
}
CF412D Giving Awards
题意:给定一有向图,保证没有反向平行边,求其补图的哈密顿回路。
题解:DFS 树上的后序遍历。
#include<bits/stdc++.h>
using namespace std;
int getint(){ int x;scanf("%d",&x);return x; }
const int N=1e5+10,M=6e5+10;
struct bian{
int l,e,n;
};
bian b[M];
int s[N],tot=0;
void add(int x,int y){
tot++;
b[tot].e=y;
b[tot].n=s[x];
s[x]=tot;
}
bool vis[N];
void ss(int x){
vis[x]=1;
for(int i=s[x];i;i=b[i].n){
if(vis[b[i].e])continue;
ss(b[i].e);
}
printf("%d ",x);
}
int main(){
int n=getint(),m=getint();
for(int i=0;i<m;i++){
int x=getint(),y=getint();
add(x,y);
}
for(int i=1;i<=n;i++)if(!vis[i])ss(i);
}
CF858F Wizard's Tour
题意:将无向图的编辑化为多个 ((u,v),(v,w))。
题解:DFS,贪心,可能多余出来的一条边留给父亲。
#include<bits/stdc++.h>
using namespace std;
int getint(){ int x;scanf("%d",&x);return x; }
const int N=2e5+10,M=4e5+10;
struct bian{
int l,e,n;
};
bian b[M];
int s[N],tot=1;
void add(int x,int y){
tot++;
b[tot].e=y;
b[tot].n=s[x];
s[x]=tot;
}
vector<tuple<int,int,int> >v;
bool vis[N];
void ss(int x,int fa){
vis[x]=1;
int lst=0;
for(int i=s[x];i;i=b[i].n){
if(i==(fa^1))continue;
if(!vis[b[i].e])ss(b[i].e,i);
if(!b[i].l){
if(lst){
b[i].l=1; b[i^1].l=1;
b[lst].l=1; b[lst^1].l=1;
v.emplace_back(b[lst].e,x,b[i].e);
lst=0;
}else lst=i;
}
}
if(lst&&fa){
b[fa].l=1; b[fa^1].l=1;
b[lst].l=1; b[lst^1].l=1;
v.emplace_back(b[lst].e,x,b[fa^1].e),lst=0;
}
}
int main(){
int n=getint(),m=getint();
for(int i=0;i<m;i++){
int x=getint(),y=getint();
add(x,y);
add(y,x);
}
for(int i=1;i<=n;i++)if(!vis[i])ss(i,0);
printf("%d
",v.size());
for(auto i:v)printf("%d %d %d
",get<0>(i),get<1>(i),get<2>(i));
}
洛谷 P5540 [BalkanOI2011] timeismoney | 最小乘积生成树
P5540 [BalkanOI2011] timeismoney | 最小乘积生成树
题意:无向图,每条边有权值 (a_i,b_i),求生成树,最小化 ((sum_i a_i) imes (sum_i b_i))
题解:最优解一定在下凸包上,于是我们凸包上二分。具体地,我们令斜率为 (k),则令边权为 (ka+b) 并求 MST。
#include<bits/stdc++.h>
using namespace std;
inline int getint(){
int ans=0,f=1;
char c=getchar();
while(c<'0'||c>'9'){
if(c=='-')f=-1;
c=getchar();
}
while(c>='0'&&c<='9'){
ans=ans*10+c-'0';
c=getchar();
}
return ans*f;
}
#define ll long long
#define pii pair<int,int>
#define fi first
#define se second
const int N=200,M=10010;
struct bian{
int s,t,x,y;
};
bian b[M];
int n,m;
double k1,k2;
inline bool operator<(bian a,bian b){
return a.x*k1+a.y*k2<b.x*k1+b.y*k2;
}
int f[N];inline int _(int x){ return x==f[x]?x:f[x]=_(f[x]); }
inline ll abs(pii p){
return p.fi*1ll*p.se;
}
inline pii mst(double k1,double k2){
::k1=k1;::k2=k2;
sort(b,b+m);
for(int i=0;i<=n;i++)f[i]=i;
pii ans;
int cnt=0;
for(int i=0;i<m;i++){
int x=_(b[i].s),y=_(b[i].t);
if(x==y)continue;
ans.fi+=b[i].x;
ans.se+=b[i].y;
f[x]=y;
++cnt;
if(cnt==n-1)break;
}
return ans;
}
inline pii solve(pii p,pii q,int dep=0){
pii ans=abs(p)<abs(q)?p:q;
if(p.fi==q.fi||p.se==q.se)return ans;
double k=(q.se-p.se*1.0)/(p.fi-q.fi);
pii r=mst(k,1);
//cerr<<string(dep,' ')<<"solve "<<p.fi<<" "<<p.se<<" "<<q.fi<<" "<<q.se<<" "<<r.fi<<" "<<r.se<<" "<<ans<<endl;
if(r.fi*k+r.se-
q.fi*k-q.se>-1e-8)return ans;
pii t=solve(r,p,dep+1);
ans=abs(ans)<abs(t)?ans:t;
t=solve(q,r,dep+1);
ans=abs(ans)<abs(t)?ans:t;
return ans;
}
inline pii solve(){
pii p1,p2;
p1=mst(1,0);
p2=mst(0,1);
if(p1.fi<0||p2.se<0)return pii(0,0);
return solve(p1,p2);
}
int main(){
n=getint(),m=getint();
for(int i=0;i<m;i++)b[i].s=getint(),b[i].t=getint(),b[i].x=getint(),b[i].y=getint();
pii ans=solve();
cout<<ans.first<<" "<<ans.second<<endl;
}