9.20洛谷图论

一。tanjian算法(强连通图)

int s[MAXN], stop;
int dfn[MAXN], low[MAXN];
int scccnt, sccnum[MAXN];
int dfscnt;

inline void tarjan(int now){
    dfn[now] = low[now] = ++dfscnt;
    s[stop++] = now;
    for (int i = he[now]; i != 0 ; i = ne[i]){
        if (!dfn[ed[i]]) {
            tarjan(ed[i]);
            low[now] = min(low[now], low[ed[i]]);
        } else if(!sccnum[ed[i]]) {
            low[now] = min(low[now], dfn[ed[i]]);
        }
    }

    if (dfn[now] == low[now]) {
        scccnt++;
        do {
            sccnum[s[--stop]] = scccnt;
        } while(s[stop] != now);
    }
}

 

 

练习:(割点割边+缩点+dfs)模板:P3387

 1 #include<iostream>
 2 #include<cstring>
 3 using namespace std;
 4 struct sb
 5 {
 6     int to,nx;
 7 }g[200001];
 8 int x[100001],y[100001],t[100001];
 9 int cnt,list[200001];
10 void add(int x,int y)
11 {
12     g[++cnt].to=y; g[cnt].nx=list[x]; list[x]=cnt;
13 }
14 int dfn[100001],low[100001],num,stack[100010],top,color[100010],col,sum[100010],vis[100010];
15 void tarjan(int x)
16 {
17     dfn[x]=++num;
18     low[x]=num;
19     vis[x]=1;
20     stack[++top]=x;
21     for (int i=list[x];i;i=g[i].nx)
22     {
23         int y=g[i].to;
24         if (!dfn[y])
25         {
26             tarjan(y);
27             low[x]=min(low[x],low[y]);
28         }
29         else if (vis[y]) low[x]=min(low[x],dfn[y]);
30     }
31     if (dfn[x]==low[x]) 
32     {
33         ++col;
34         while (stack[top+1]!=x)
35         {
36             color[stack[top]]=col;
37             sum[col]+=t[stack[top]];
38             vis[stack[top--]]=false;
39         }
40     }
41 }
42 int f[100010];
43 void dfs(int x)
44 {
45     if (f[x]) return;
46     f[x]=sum[x];
47     int maxsum=0;
48     for (int i=list[x];i;i=g[i].nx)
49     {
50         int y=g[i].to;
51         if (!f[y]) dfs(y);
52         maxsum=max(maxsum,f[y]);
53     }
54     f[x]+=maxsum;
55 }
56 int main ()
57 {
58     int n,m;
59     cin>>n>>m;
60     for (int i=1;i<=n;i++) cin>>t[i];
61     for (int i=1;i<=m;i++)
62     {
63         cin>>x[i]>>y[i];
64         add(x[i],y[i]);
65     }
66     for (int i=1;i<=n;i++)
67       if (!dfn[i]) tarjan(i);
68     memset(g,0,sizeof(g));
69     memset(list,0,sizeof(list));
70     cnt=0;
71     for (int i=1;i<=m;i++)
72        if (color[x[i]]!=color[y[i]])
73          add(color[x[i]],color[y[i]]);
74     int ans=0;
75     for (int i=1;i<=col;i++)
76       if (!f[i])
77       {
78            dfs(i);
79            ans=max(ans,f[i]);
80       }
81     cout<<ans;
82     
83 } 

 

 

二。树的直径   树的重心(分治)

int sz[MAXN];
inline int dfs_sz(int now, int f){
    sz[now] = 1;
    for(int i = he[now]; i; i = ne[i]){
        Edge& e = ed[i];
        if(!vis[e.to] && e.to != f){
            sz[now] += dfs_sz(e.to, now);
        }
    }
    return sz[now];
}

inline int dfs_find(int now, int f, int tot){
    for(int i = he[now]; i; i = ne[i]){
        Edge& e = ed[i];
        if(!vis[e.to] && e.to != f){
            if(sz[e.to]*2 > tot) return dfs_find(e.to, now, tot);
        }
    }
    return now;
}


inline int findg(int s){
    dfs_sz(s, -1);
    return dfs_find(s, -1, sz[s]);
}

 

练习:POJ1655

 

三。最近公共祖先

(倍增LCA)枚举答案的二进制位

int fa[maxn][20], dep[maxn], d[maxn];

void build_lca(int now){
    for(int i = 1 ; i < 20 && fa[now][i] ; i++){
        fa[now][i] = fa[fa[now][i-1]][i-1];
    }
    
    for(int i = he[now]; i ; i = ne[i]){
        Edge &e = ed[i];
        if(e.to == fa[now][0])  continue;
        fa[e.to][0] = now;
        dep[e.to] = dep[now] + 1;
        d[e.to] = d[now] + e.dist;
        build_lca(e.to);
    }
}

int get_lca(int x,int y)
{
    if(dep[x] != dep[y]){
        if(dep[y] > dep[x])  swap(X,y);
        
        for(int i = 19 ; i >= 0 ; i--){
            if(dep[fa[x][i]] >= dep[y])  x = fa[x][i];
        }
    }
    
    if(x == y)  return x;
    
    for(int i = 19 ; i >= 0 ; i--){
        if(fa[x][i] != fa[y][i]) {
            x = fa[x][i];
            y = fa[y][i];
        }
    }
    
    return fa[x][0];
} 

 

例题:P1073  P2746 P2860

转载于:https://www.cnblogs.com/zyddd915/p/11558964.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值