CF757F Team Rocket Rises Again(支配树模板题)

题目要求在无向图中找到除起点s外,对最短路影响最大的节点u。通过构建最短路图并建立支配树,找出每个节点的最近必经点,进而确定影响最大的节点。解决此问题的关键在于理解和应用支配树的数据结构。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接

题意:无向图中有n个点,m条边,现给你一个起点s。要求点u有:

  1. u!=s
  2. 原图中去掉u后改变的最短路最多

现有一种数据结构可以维护出在有向图中从起点到每个点的路径中的距离该点最近的必经点。

那么最短路图中每个必经点所控制的点的最大值就是我们所需要的答案。

这题的思路也就是这么简单,关键是学会支配树的基本用法。

支配树推荐学习博客

做法:

  1. 首先维护出起点到每个点的最短路;
  2. 然后根据最短路画出最短路图;
  3. 然后对最短路图建树;
  4. 从后往前把当前点v的权值贡献给idom(v);
  5. 求出权值最大的点。

Upd:2019/7/29 加了个初始化dfn数组

#include<algorithm>
#include<vector>
#include<iostream>
#include<math.h>
#include<cstring>
#include<string>
#include<stack>
#include<map>
#include<set>
#include<unordered_map>
#include<queue>

#define qcin; ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define pb push_back
#define mp make_pair
#define clr(x) memset(x,0,sizeof x)
#define fmax(x) memset(x,0x3f,sizeof x)
#define finit(x) memset(x,-1,sizeof x)

#define dis(l,r) r-l+1
#define gstr(str) scanf("%s",str)
#define glen(str) strlen(str)
using namespace std;

typedef long long ll;

namespace Input
{
    const int BUF = 65536;
    char buf[BUF + 1];
    char *head = buf, *tail = buf;
}
inline char inputchar()
{
    using namespace Input;
    if(head == tail)
        *(tail = (head = buf) + fread(buf, 1, BUF, stdin)) = 0;
    return *head++;
}
inline void io(int &ret){
    char ch = inputchar();
    while(ch < '0' || ch > '9')
        ch = inputchar();
    ret = ch - '0';
    ch = inputchar();
    while(ch >= '0' && ch <= '9'){
        ret = ret * 10 + ch - '0';
        ch = inputchar();
    }
}
inline void sio(int &ret){
    ret = 0;
    char ch = inputchar();
    while((ch < '0' || ch > '9') && ch != '-')
        ch = inputchar();
    bool neg = false;
    if(ch == '-')
        neg = true, ch = inputchar();
    while(ch >= '0' && ch <= '9')
    {
        ret = ret * 10 + ch - '0';
        ch = inputchar();
    }
    if(neg)
        ret = -ret;
}

typedef pair<ll,ll>pll;
const int maxn = 5e5+10;
const ll mod = 2148473648;
typedef ll arr[maxn];
typedef char str[maxn];
void file(int x){if(x&&fopen("in.txt","r")){freopen("in.txt","r",stdin);if(x==2)freopen("1.txt","w",stdout);}}
struct node{
    int to,cst,nxt;
}E[maxn*10];

const double pi=acos(-1);
arr dfn,id,h,anc,sdom,idom,pre,dom,d,fa,best,H,num;
int n,tot,pos,m,st;
void addedge(ll h[],int u,int v,int w=0){
    E[tot].to=v;
    E[tot].cst=w;
    E[tot].nxt=h[u];
    h[u]=tot++;
}

void dfs(int x){
    dfn[x]=++pos,id[pos]=x;
    for(int i=h[x];~i;i=E[i].nxt){
        int y=E[i].to;
        if(!dfn[y]){
            dfs(y);
            fa[dfn[y]]=dfn[x];
        }
    }
}

int get(int x){
    if(anc[x]==x)return x;
    int y=get(anc[x]);
    if(sdom[best[x]]>sdom[best[anc[x]]]){
        best[x]=best[anc[x]];
    }
    anc[x]=y;
    return y;
}

void tarjin(){
    for(int y=pos;y>1;y--){

        int x=fa[y];
        int p=id[y];
        for(int i=pre[p];~i;i=E[i].nxt){
            int z=E[i].to;
            z=dfn[z];
            if(!z)continue;
            get(z);
            sdom[y]=min(sdom[y],sdom[best[z]]);
        }

        addedge(dom,sdom[y],y);
        anc[y]=x;
        for(int i=dom[x];~i;i=E[i].nxt){
            int z=E[i].to;
            get(z);
            if(sdom[best[z]]<x)idom[z]=best[z];
            else idom[z]=x;
        }
        dom[x]=-1;
    }
    for(int i=2;i<=pos;i++){
        if(idom[i]!=sdom[i]){
            idom[i]=idom[idom[i]];
        }
        addedge(dom,idom[i],i);
    }
    idom[1]=0;
}


void dij(int st){
    fmax(d);
    static int vis[maxn];
    priority_queue<pll>Q;
    d[st]=0;
    Q.push(mp(0,st));
    while(Q.size()){
        int u=Q.top().second;
        Q.pop();
        if(vis[u])continue;
        vis[u]=1;
        for(int i=H[u];~i;i=E[i].nxt){
            int v=E[i].to;
            ll cost=d[u]+E[i].cst;
            if(cost<d[v]){
                d[v]=cost;
                Q.push(mp(-cost,v));
            }
        }
    }
}

void init(){
    finit(dom);finit(H);finit(h);finit(pre);
    clr(num);clr(dfn);
    for(int i=0;i<=n;i++){
        sdom[i]=anc[i]=best[i]=i;
    }
    tot=0;
    pos=0;
}

int main(){
    file(1);
    int u,v,w;
    io(n),io(m),io(st);
    init();
    while(m--){
        io(u),io(v),io(w);
        addedge(H,u,v,w);
        addedge(H,v,u,w);
    }
    dij(st);
    for(int u=1;u<=n;u++){
        for(int i=H[u];~i;i=E[i].nxt){
            int v=E[i].to;
            if (d[u]+E[i].cst==d[v]){
                addedge(h,u,v);
                addedge(pre,v,u);
            }
        }
    }
    dfs(st);
    tarjin();
    int ans=0;
    for(int i=pos;i>1;i--){
        num[i]++;
        num[idom[i]]+=num[i];
        ans=max((ll)ans,num[i]);
    }
    printf("%d\n",ans);
    return 0;
}

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值