7.9图论
T1[USACO05DEC] 布局
差分约束模板题,注意判断当 1 − n 1-n 1−n可以合法时其他点是否可以合法
#include<bits/stdc++.h>
#define FOR(i,a,b) for (int i=a;i<=b;i++)
#define GO(u) for (int j=f[u];j!=-1;j=nxt[j])
#define MEM0(i) memset(i,0,sizeof(i));
#define MAX(i) memset(i,0x3f,sizeof(i));
using namespace std;
const int N=2e6+5;
int n,l,d;
int tot=0,f[N],nxt[N<<1],cnt[N];
int dis[N],vis[N],Ans;
queue <int> q;
struct E
{
int u,v,w;
}e[N<<1];
void Add(int u,int v,int w)
{
tot++;
nxt[tot]=f[u];
f[u]=tot;
e[tot]=(E){u,v,w};
return;
}
int read()
{
int x=0,f=1;
char c=getchar();
while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
while (c>='0'&&c<='9') {x=(x<<1)+(x<<3)+c-'0';c=getchar();}
return f*x;
}
int SPFA(int S)
{
MEM0(cnt);
MEM0(vis);
MAX(dis);
int no=dis[0];
while (q.size()) q.pop();
q.push(S);
vis[S]=1;
dis[S]=0;
while (q.size())
{
int tmp=q.front();
q.pop();
vis[tmp]=0;
GO(tmp)
{
int v=e[j].v;
if (dis[v]>dis[tmp]+e[j].w)
{
cnt[v]=cnt[tmp]+1;
dis[v]=dis[tmp]+e[j].w;
if (cnt[v]>=n) return -1;
if (!vis[v])
{
vis[v]=1;
q.push(v);
}
}
}
}
if (dis[n]==no) return -2;
else return dis[n];
}
int main()
{
memset(f,-1,sizeof(f));
n=read(),l=read(),d=read();
FOR(i,1,l)
{
int x=read(),y=read(),z=read();
Add(x,y,z);
}
FOR(i,1,d)
{
int x=read(),y=read(),z=read();
Add(y,x,-z);
}
FOR(i,1,n) Add(n+1,i,0);
Ans=SPFA(n+1);
if (Ans!=-1) Ans=SPFA(1);
printf("%d\n",Ans);
return 0;
}
T2 NOIP2013 货车运输
建最大生成树,维护两点间最小的边权值,LCA,LCT,树剖
#include<bits/stdc++.h>
using namespace std;
int n,m,q,first[100010],next[1000010],tot=0,tmp=0,father[100010],getthis[1000010]={0},total=0,sum=0,My_ans[1000010],vis[100010]={0};
int grand[100010][100],gw[100010][100],maxn,depth[100010];
struct csx
{
int from,to,weight;
}edge[1000010];
struct csx2
{
int from,to,weight;
}line[1000010];
bool cmp(const csx a,const csx b)
{
if (a.weight>b.weight) return true;
else return false;
}
void add(int u,int v,int w)
{
tot++;
edge[tot].from=u;
edge[tot].to=v;
edge[tot].weight=w;
return;
}
void add2(int u,int v,int w)
{
total++;
line[total].from=u;
line[total].to=v;
line[total].weight=w;
next[total]=first[u];
first[u]=total;
return;
}
int getfather(int x)
{
int root=x;
while (father[root]!=root) root=father[root];
int y=x;
while (y!=root)
{
int k=father[y];
father[y]=root;
y=k;
}
return root;
}
void join(int x,int y)
{
int fx=getfather(x),fy=getfather(y);
if (fx!=fy) father[fx]=fy;
return;
}
void dfs(int x)
{
vis[x]=1;
for (int i=1;i<=maxn;i++)
{
grand[x][i]=grand[grand[x][i-1]][i-1];
gw[x][i]=min(gw[x][i-1],gw[grand[x][i-1]][i-1]);
}
int j=first[x];
while (j!=-1)
{
int u=line[j].from,v=line[j].to,w=line[j].weight;
if (grand[x][0]!=v)
{
grand[v][0]=x;
gw[v][0]=w;
depth[v]=depth[x]+1;
dfs(v);
}
j=next[j];
}
return;
}
int LCA_ans(int a,int b)
{
int ans=INT_MAX;
if (depth[a]>depth[b]) swap(a,b);
for (int i=maxn;i>=0;i--) if (depth[a]<depth[b]&&depth[a]<=depth[grand[b][i]])
{
ans=min(ans,gw[b][i]);
b=grand[b][i];
}
for (int i=maxn;i>=0;i--)
{
if (grand[a][i]!=grand[b][i])
{
ans=min(ans,gw[b][i]);
ans=min(ans,gw[a][i]);
a=grand[a][i];
b=grand[b][i];
}
}
if (a!=b)
{
ans=min(ans,gw[a][0]);
ans=min(ans,gw[b][0]);
}
return ans;
}
void test1()
{
for (int i=1;i<=total;i++) cout<<line[i].from<<" "<<line[i].to<<" "<<line[i].weight<<endl;
return;
}
int main()
{
memset(gw,0x3f,sizeof(gw));
memset(first,-1,sizeof(first));
memset(next,-1,sizeof(next));
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++) father[i]=i;
for (int i=1;i<=m;i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
if (u!=v) add(u,v,w);
}
sort(edge+1,edge+1+tot,cmp);
for (int i=1;i<=tot;i++) if (tmp<n-1)
{
int x=edge[i].from,y=edge[i].to;
int fx=getfather(x),fy=getfather(y);
if (fx!=fy)
{
tmp++;
getthis[i]=true;
join(x,y);
}
}
for (int i=1;i<=tot;i++) if (getthis[i])
{
int u=edge[i].from,v=edge[i].to,w=edge[i].weight;
add2(u,v,w);
add2(v,u,w);
}
maxn=log2(n);
depth[1]=1;
dfs(1);
for (int i=1;i<=n;i++)
{
if (vis[i]==0)
{
depth[i]=1;
dfs(i);
}
}
scanf("%d",&q);
for (int i=1;i<=q;i++)
{
int l,r,dis;
scanf("%d%d",&l,&r);
int fl=getfather(l),fr=getfather(r);
if (fl!=fr||l==r)
{
My_ans[++sum]=-1;
continue;
}
dis=LCA_ans(l,r);
My_ans[++sum]=dis;
}
for (int i=1;i<=sum;i++) printf("%d\n",My_ans[i]);
return 0;
}
T3 [HNOI2012]矿场搭建
几题里相对难的一题,先把所有割点标记出来。
对于所有割点割出来的一系列连通块:
1,若该连通块不与割点相邻,它至少有2个出口,
a
n
s
1
+
=
2
,
a
n
s
2
∗
=
s
i
z
∗
(
s
i
z
−
1
)
/
2
ans1+=2,ans2*=siz*(siz-1)/2
ans1+=2,ans2∗=siz∗(siz−1)/2
2,若该连通块只与一个割点相邻,它只需要1个出口,
a
n
s
1
+
+
,
a
n
s
2
∗
=
s
i
z
ans1++,ans2*=siz
ans1++,ans2∗=siz
3,若该连通块与大于等于两个割点相邻,即使他取走任意一个割点,都可以跑出去别的连通块找出口,该连通块不需要出口
#include<bits/stdc++.h>
#define FOR(i,a,b) for (ll i=a;i<=b;i++)
#define FFOR(i,a,b) for (ll i=a;i>=b;i--)
#define GO(u) for (ll j=f[u];j!=-1;j=nxt[j])
#define mem(i) memset(i,0,sizeof(i));
#define MEM(i) memset(i,0x3f,sizeof(i));
#define Mem(i) memset(i,-1,sizeof(i));
using namespace std;
typedef long long ll;
const ll N=2e6+5;
ll n,m,tpp=0,g,x,y,ans1,ans2,size,tmp;
ll tot,f[N],nxt[N<<1],dfn[N],low[N],tag[N],vis[N],dfnn;
struct E
{
ll u,v;
}e[N<<1];
void Init()
{
tot=dfnn=ans1=g=n=0;
ans2=1;
Mem(f);
mem(dfn);
mem(low);
mem(nxt);
mem(tag);
mem(vis);
return;
}
void Add(ll u,ll v)
{
tot++;
nxt[tot]=f[u];
f[u]=tot;
e[tot]=(E){u,v};
return;
}
void Tarjan(ll u,ll fa)
{
dfn[u]=low[u]=++dfnn;
ll sons=0;
GO(u)
{
ll v=e[j].v;
if (!dfn[v])
{
Tarjan(v,u);
sons++;
low[u]=min(low[u],low[v]);
if (low[v]>=dfn[u]&&fa!=-1) tag[u]=1;
}
else low[u]=min(low[u],dfn[v]);
}
if (sons>=2&&fa==-1) tag[u]=1;
return;
}
void DFS(ll u)
{
vis[u]=g;
size++;
GO(u)
{
ll v=e[j].v;
if (tag[v]&&vis[v]!=g)
{
tmp++;
vis[v]=g;
}
else if (!vis[v]) DFS(v);
}
return;
}
int main()
{
// freopen("testdata.in","r",stdin);
while (scanf("%lld",&m)&&m!=0)
{
Init();
FOR(i,1,m) scanf("%lld%lld",&x,&y),Add(x,y),Add(y,x),n=max(n,y),n=max(n,x);
FOR(i,1,n) if (!dfn[i]) Tarjan(i,-1);
FOR(i,1,n) if (!tag[i]&&!vis[i])
{
size=0,tmp=0;
g++;
DFS(i);
if (tmp==1)
{
ans1++;
ans2*=size;
}
else if (tmp==0)
{
ans1+=2;
ans2*=size*(size-1)/2;
}
}
printf("Case %lld: %lld %lld\n",++tpp,ans1,ans2);
}
return 0;
}
T5 CF825E Minimal Labels
对于每一个 a [ i ] < a [ j ] a[i]<a[j] a[i]<a[j]的条件,连 j − > i j->i j−>i,意味着第 j j j个必须比第 i i i个大,拓扑排序贪心让大数排后面
#include<bits/stdc++.h>
#define FOR(i,a,b) for (int i=a;i<=b;i++)
#define FFOR(i,a,b) for (int i=a;i>=b;i--)
#define GO(u) for (int j=f[u];j!=-1;j=nxt[j])
#define mem(i) memset(i,0,sizeof(i));
#define MEM(i) memset(i,0x3f,sizeof(i));
using namespace std;
const int N=2e5+5;
int n,m;
int tot=0,f[N],nxt[N],ans[N],d[N],x,y,pos[N],out[N];
priority_queue <int> q1,q2;
struct E
{
int u,v;
}e[N<<1];
void Add(int u,int v)
{
tot++;
nxt[tot]=f[u];
f[u]=tot;
e[tot]=(E){u,v};
d[v]++;
return;
}
int main()
{
memset(f,-1,sizeof(f));
scanf("%d%d",&n,&m);
FOR(i,1,m) scanf("%d%d",&x,&y),Add(y,x);
FOR(i,1,n) if (!d[i]) q1.push(i);
while (q1.size())
{
int tmp=q1.top();
q1.pop();
ans[++ans[0]]=tmp;
GO(tmp)
{
int v=e[j].v;
d[v]--;
if (!d[v]) q1.push(v);
}
}
FOR(i,1,n) out[ans[i]]=n-i+1;
FOR(i,1,n) printf("%d ",out[i]);
return 0;
}