支配树

原图-->dfs图-->支配树

支配点:支配树中Y的祖先加上它自己 都是Y的支配点.去掉支配点使得在原图中源点无法到达Y(即必经点)

最近支配点:支配树中Y最近的祖先

半支配点:在dfs tree中可以通过非dfs tree中的边到达y的深度最小的节点x 为y的半支配点

Lengauer-Tarjan算法 O(nlogn)

利用并查集

1.dfs构建搜索树 计算出dfn

2.按时间戳从大到小的顺序算出每个节点的半支配点

3.按照时间戳从小到大的顺序把半支配点≠支配点的节点进行修正

HDU 4694

/*Huyyt*/
#include<bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const double eps = 1e-8;
const int dir[8][2] = {{0, 1}, {1, 0}, {0, -1}, { -1, 0}, {1, 1}, {1, -1}, { -1, -1}, { -1, 1}};
const int mod = 1e9 + 7, gakki = 5 + 2 + 1 + 19880611 + 1e9;
const int MAXN = 5e5 + 5, MAXM = 2e5 + 5;
const int MAXQ = 100010, INF = 1e9;
/*int to[MAXM << 1], nxt[MAXM << 1], Head[MAXN], tot = 1;
int TO[MAXM << 1], NXT[MAXM << 1], HEAD[MAXN], TOT = 1;
ll cost[MAXM << 1];
struct node
{
        int u, v;
        ll c;
} edge[MAXM];
inline void addedge(int u, int v)
{
        to[++tot] = v;
        nxt[tot] = Head[u];
        //cost[tot] = c;
        Head[u] = tot;
}*/

inline void read(int &v)
{
        v = 0;
        char c = 0;
        int p = 1;
        while (c < '0' || c > '9')
        {
                if (c == '-')
                {
                        p = -1;
                }
                c = getchar();
        }
        while (c >= '0' && c <= '9')
        {
                v = (v << 3) + (v << 1) + c - '0';
                c = getchar();
        }
        v *= p;
}
int dfn[MAXN], idom[MAXN], sdom[MAXN];
int son[MAXN], id[MAXN], fa[MAXN], f[MAXN];
int ans[MAXN];
int cnt;
int n, m;
vector<int> yuantu[MAXN], fantu[MAXN], zhipei[MAXN];
int findfather(int x)
{
        if (f[x] == x)
        {
                return x;
        }
        int y = findfather(f[x]);
        if (sdom[son[x]] > sdom[son[f[x]]])
        {
                son[x] = son[f[x]];
        }
        return  f[x] = y;
}
void dfs(int u)
{
        id[dfn[u] = ++cnt] = u;
        for (int v, i = 0; i < yuantu[u].size(); i++)
        {
                if (v = yuantu[u][i], !dfn[v])
                {
                        dfs(v), fa[dfn[v]] = dfn[u];
                }
        }
}
inline void tarjan(int s)
{
        for (int i = 1; i <= n; i++)
        {
                f[i] = sdom[i] = son[i] = fa[i] = i;
                dfn[i] = 0;
        }
        cnt = 0, dfs(s);
        int k, x;
        for (int i = cnt; i > 1; i--)
        {
                for (int v, j = 0; j < fantu[id[i]].size(); j++)
                {
                        if (v = fantu[id[i]][j], dfn[v])
                        {
                                findfather(k = dfn[v]), sdom[i] = sdom[i] < sdom[son[k]] ? sdom[i] : sdom[son[k]];
                        }
                }
                zhipei[sdom[i]].push_back(i), f[i] = x = fa[i];
                for (int v, j = 0; j < zhipei[f[i]].size(); j++)
                {
                        v = zhipei[f[i]][j], findfather(k = v), idom[k] = sdom[son[k]] < x ? son[k] : x;
                }
                zhipei[x].clear();
        }
        for (int i = 2; i <= cnt; zhipei[id[idom[i]]].push_back(id[i]), i++)
        {
                if (idom[i] != sdom[i])
                {
                        idom[i] = idom[idom[i]];
                }
        }
}
void mp(int u, int p)
{
        ans[u] = p;
        for (int v, i = 0; i < zhipei[u].size(); i++)
        {
                v = zhipei[u][i], mp(v, p + v);
        }
}
int main()
{
        ios_base::sync_with_stdio(0);
        cin.tie(0);
        int T;
        int u, v;
        //freopen("jqkout.txt", "w", stdout);
        while (scanf("%d %d", &n, &m) == 2)
        {
                for (int i = 0; i <= n; i++)
                {
                        yuantu[i].clear(), fantu[i].clear(), zhipei[i].clear();
                }
                for (int i = 1; i <= m; i++)
                {
                        scanf("%d %d", &u, &v);
                        yuantu[u].push_back(v), fantu[v].push_back(u);
                }
                tarjan(n);
                mp(n, n);
                for (int i = 1; i <= n; i++)
                {
                        cout << ans[i];
                        if (i != n)
                        {
                                cout << " ";
                        }
                        else
                        {
                                cout << endl;
                        }
                        ans[i] = 0;
                }
        }
        return 0;
}
View Code

Opencup Petrozavodsk Winter Training Camp 2018
Day 8: Saratov SU Contest, Tuesday, February 8, 2018
Problem L. Increasing Costs 

求出支配树 支配树上的点在DAG中入度为1的话 那条边则为必经边

/*Huyyt*/
#include<bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const double eps = 1e-8;
const int dir[8][2] = {{0, 1}, {1, 0}, {0, -1}, { -1, 0}, {1, 1}, {1, -1}, { -1, -1}, { -1, 1}};
const int mod = 1e9 + 7, gakki = 5 + 2 + 1 + 19880611 + 1e9;
const int MAXN = 1e6 + 5, MAXM = 1e6 + 5;
const int MAXQ = 100010, INF = 1e9;
int to[MAXM << 1], nxt[MAXM << 1], Head[MAXN], tot = 1;
ll cost[MAXM << 1];
int preedge[MAXN];
int du[MAXN];
struct node
{
        int u, v;
        ll c;
} edge[MAXM << 1];
inline void addedge(int u, int v, ll c)
{
        to[++tot] = v;
        nxt[tot] = Head[u];
        cost[tot] = c;
        Head[u] = tot;
}
inline void read(int &v)
{
        v = 0;
        char c = 0;
        int p = 1;
        while (c < '0' || c > '9')
        {
                if (c == '-')
                {
                        p = -1;
                }
                c = getchar();
        }
        while (c >= '0' && c <= '9')
        {
                v = (v << 3) + (v << 1) + c - '0';
                c = getchar();
        }
        v *= p;
}
int dp[MAXN];
ll dis[MAXN];
bool visit[MAXN];
priority_queue < pair<ll, int>, vector<pair<ll, int> >, greater<pair<ll, int> > >que;
bool chose[MAXM];
int dfn[MAXN], idom[MAXN], sdom[MAXN];
int son[MAXN], id[MAXN], fa[MAXN], f[MAXN];
int ans[MAXN];
int cnt;
int n, m;
vector<int> yuantu[MAXN], fantu[MAXN], zhipei[MAXN];
int findfather(int x)
{
        if (f[x] == x)
        {
                return x;
        }
        int y = findfather(f[x]);
        if (sdom[son[x]] > sdom[son[f[x]]])
        {
                son[x] = son[f[x]];
        }
        return  f[x] = y;
}
void dfs(int u)
{
        id[dfn[u] = ++cnt] = u;
        for (int v, i = 0; i < yuantu[u].size(); i++)
        {
                if (v = yuantu[u][i], !dfn[v])
                {
                        dfs(v), fa[dfn[v]] = dfn[u];
                }
        }
}
inline void tarjan(int s)
{
        for (int i = 1; i <= n; i++)
        {
                f[i] = sdom[i] = son[i] = fa[i] = i;
                dfn[i] = 0;
        }
        cnt = 0, dfs(s);
        int k, x;
        for (int i = cnt; i > 1; i--)
        {
                for (int v, j = 0; j < fantu[id[i]].size(); j++)
                {
                        if (v = fantu[id[i]][j], dfn[v])
                        {
                                findfather(k = dfn[v]), sdom[i] = sdom[i] < sdom[son[k]] ? sdom[i] : sdom[son[k]];
                        }
                }
                zhipei[sdom[i]].push_back(i), f[i] = x = fa[i];
                for (int v, j = 0; j < zhipei[f[i]].size(); j++)
                {
                        v = zhipei[f[i]][j], findfather(k = v), idom[k] = sdom[son[k]] < x ? son[k] : x;
                }
                zhipei[x].clear();
        }
        for (int i = 2; i <= cnt; zhipei[id[idom[i]]].push_back(id[i]), i++)
        {
                if (idom[i] != sdom[i])
                {
                        idom[i] = idom[idom[i]];
                }
        }
}
void get_ans(int u)
{
        dp[u] = 1;
        for (int v, i = 0; i < zhipei[u].size(); i++)
        {
                v = zhipei[u][i];
                //cout << u << " " << v << endl;
                get_ans(v);
                dp[u] += dp[v];
        }
        if (du[u] == 1)
        {
                ans[preedge[u]] = dp[u];
        }
}
int main()
{
        ios_base::sync_with_stdio(0);
        cin.tie(0);

        int T;
        //freopen("jqkout.txt", "w", stdout);
        int u, v, c;
        read(n), read(m);
        for (int i = 1; i <= m; i++)
        {
                chose[i * 2] = chose[i * 2 - 1] = false;
                //scanf("%d %d %d", &u, &v, &c);
                read(u), read(v), read(c);
                edge[i * 2 - 1].u = u, edge[i * 2 - 1].v = v, edge[i * 2 - 1].c = c;
                edge[i * 2].u = v, edge[i * 2].v = u, edge[i * 2].c = c;
                addedge(u, v, c);
                addedge(v, u, c);
        }
        for (int i = 1; i <= n; i++)
        {
                visit[i] = false;
                dis[i] = LLONG_MAX;
        }
        dis[1] = 0;
        pair<ll, int> cnt;
        que.push(make_pair(0, 1));
        while (!que.empty())
        {
                cnt = que.top();
                que.pop();
                visit[cnt.second] = true;
                for (int i = Head[cnt.second]; i; i = nxt[i])
                {
                        int v = to[i];
                        if (visit[v])
                        {
                                continue;
                        }
                        if (dis[v] > dis[cnt.second] + cost[i])
                        {
                                dis[v] = dis[cnt.second] + cost[i];
                                que.push(make_pair(dis[v], v));
                        }
                }
        }
        //        for (int i = 1; i <= n; i++)
        //        {
        //                cout << dis[i] << " ";
        //        }
        //        cout << endl;
        for (int i = 1; i <= 2 * m; i++)
        {
                if (dis[edge[i].v] == dis[edge[i].u] + edge[i].c)
                {
                        //cout << edge[i].u << " " << edge[i].v << endl;
                        chose[i] = true;
                        yuantu[edge[i].u].push_back(edge[i].v);
                        du[edge[i].v]++;
                        preedge[edge[i].v] = (i + 1) / 2;
                        fantu[edge[i].v].push_back(edge[i].u);
                }
        }
        tarjan(1);
        get_ans(1);
        for (int i = 1; i <= m; i++)
        {
                cout << ans[i] << endl;
        }
        return 0;
}
View Code

 

posted @ 2018-07-23 22:00  Aragaki  阅读(321)  评论(0编辑  收藏  举报