codeforces 757F Team Rocket Rises Again(最短路+支配树)

来源:互联网 发布:如何下载bilibili mac 编辑:程序博客网 时间:2024/06/07 18:48

今天刚刚看了支配树,然而恕我太弱并没有看明白Lengauer-Tarjan算法,比较懵QAQ……不过我倒是学会了在DAG上构建支配树,就贴一道简单题过来吧O(∩_∩)O。

如何在DAG上求支配树?

有向无环图(DAG)里我们可以按照拓扑序构建支配树。

假设当前我们构造到拓扑序中第x个节点编号为v,那么此时支配树中已经有拓扑序第1~x-1个节点了。考虑所有能够直接到达v的节点,对于这些节点我们求出它们在支配树上的最近公共祖先Lca(所以要反向建一份图g2),这个点Lca就是点v在支配树上的父亲。

这样,支配树就建好了

用倍增求LCA的话,时间复杂度是O((n+m)log2n)。

题目链接:codeforces 757 F
题解:这个题的话,跑出最短路图,再在最短路图上建支配树,求最大的子树大小。
code(有参考网上神犇们的代码)

#include<iostream>#include<cstdio> #include<cstring>#include<algorithm>#include<cmath>#define inf 1LL<<60using namespace std;inline int read(){    char c=getchar(); int num=0,f=1;    while (c<'0'||c>'9') { if (c=='-') f=-1; c=getchar(); }    while (c<='9'&&c>='0') { num=num*10+c-'0'; c=getchar(); }    return num*f;}struct edge{    int to,ne;    long long val;}e[600005],g1[600005],g2[600005];//e[]是原图,g1[]是最短路图,g2[]和g1[]边的方向相反int head[200005],head1[200005],head2[200005];int que[4000005];int d[200005],deep[200005],siz[200005];int fa[200005][22];int S,n,m,tot,tot1,tot2,ans;bool vis[200005];long long dis[200005];void push(int x,int y,long long val){    e[++tot].to=y; e[tot].val=val; e[tot].ne=head[x]; head[x]=tot;}void push1(int x,int y){    g1[++tot1].to=y; g1[tot1].ne=head1[x]; head1[x]=tot1;}void push2(int x,int y){    g2[++tot2].to=y; g2[tot2].ne=head2[x]; head2[x]=tot2;}void spfa(int S){    for (int i=1;i<=n;i++) dis[i]=inf;    int h=0,t=1;     dis[S]=0,vis[S]=true,que[t]=S;    while (h<t)    {        int now=que[++h];        for (int i=head[now];i;i=e[i].ne)        {            int v=e[i].to;            if (dis[v]>dis[now]+e[i].val)            {                dis[v]=dis[now]+e[i].val;                if (!vis[v]) vis[v]=true,que[++t]=v;            }        }        vis[now]=false;    }}void dfs1(int now)   //找出最短路图中的边{    vis[now]=true;    for (int i=head[now];i;i=e[i].ne)    {        int v=e[i].to;        if (dis[v]==dis[now]+e[i].val)        {            push1(now,v);            push2(v,now);            d[v]++;            if (!vis[v]) dfs1(v);        }    }}void dfs2(int now)     //求出支配树各节点的size,更新答案{    siz[now]=1;    for (int i=head[now];i;i=e[i].ne)    {        int v=e[i].to;        dfs2(v);        siz[now]+=siz[v];    }    if (now!=S) ans=max(ans,siz[now]);}int lca(int x,int y)   //倍增lca{    if (x==y) return x;    if (deep[x]<deep[y]) swap(x,y);    for (int i=20;i>=0;i--)     if (deep[fa[x][i]]>=deep[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];}void topsort()     //拓扑排序{    int h=0,t=1;    que[t]=S,deep[S]=1;    while (h<t)    {        int now=que[++h];        for (int i=head1[now];i;i=g1[i].ne)        {            int v=g1[i].to;            d[v]--;            if (!d[v])             {                que[++t]=v;                int Lca=0;                for (int j=head2[v];j;j=g2[j].ne)                {                    int vv=g2[j].to;                    if (!Lca) Lca=vv;                     else Lca=lca(vv,Lca);                }   //找到v的支配点Lca,把v点加入支配树里                push(Lca,v,0);                fa[v][0]=Lca,deep[v]=deep[Lca]+1;                for (int j=1;j<=20;j++) fa[v][j]=fa[fa[v][j-1]][j-1];            }        }    }}int main(){    n=read(); m=read(); S=read();    for (int i=1;i<=m;i++)    {        int x=read(),y=read(),z=read();        push(x,y,(long long)z);        push(y,x,(long long)z);    }    spfa(S); dfs1(S);    //求最短路图    memset(head,0,sizeof(head)),tot=0;      topsort(); dfs2(S);    //建支配树    printf("%d\n",ans);    return 0;}
阅读全文
0 0
原创粉丝点击