1. 程式人生 > >【codeforces gym】Increasing Costs

【codeforces gym】Increasing Costs

有一個 friend push_back line push pri ems tor [1]

Portal --> Increasing Costs

Description

  給你一個\(n\)個點無重邊無自環的無向連通圖,每條邊有一個邊權,對於每一條邊,詢問去掉這條邊之後有多少個點到\(1\)號點的最短路會發生改變

  

Solution

  會用到一個叫做滅絕樹的東西(這個名字好霸氣qwq)

?  其實不算是什麽特別高大上的玩意:滅絕樹其實就是一個點滅絕後它的子樹內的所有點都滅絕

?  然後所謂的“滅絕”其實可以理解為。。滿足什麽條件之類的,在不同的題目中有所不同(比如說在這題裏面就是。。走不到)

?   

  然後這道題的話,因為是刪邊,我們可以將邊也看成一個點

  首先求出到\(1\)

的最短路,然後對於原圖中的一條邊權為\(w\)的邊\((i,j)\),如果說\(dis[j]=dis[i]+w\)的話,就在新圖中連\((i,num)\)\((num,j)\)的有向邊,其中\(num\)表示的是這條邊對應的節點

  註意到如果說我們將一條邊刪掉,也就是相當於將這條邊對應的節點\(num\)刪掉,由於這條邊刪掉了,由這條邊得到的最短路也就不能走了,對應到新圖中就是\(num\)這個節點不能走到,接著那些的只能由它走到的後繼也就不能走到了,以此類推

  所以我們考慮用這樣的方式建一棵樹:我們將新圖所有的邊反過來建,然後對整個反過來的新圖拓撲排序,從後往前處理每一個節點在樹上面的\(fa\)

,那麽處理到一個節點的時候,新圖中所有能走到當前節點的點的\(fa\)都已經處理好了,然後我們將當前節點的\(fa\)設為所有能走到這個節點的那些點的\(lca\)

?  這樣建完之後會發現,刪掉一條邊對應的點\(num\)之後不能走到的點其實就是其整個子樹中的點

  所以我們只要建出樹之後計算一下每個節點的子樹大小就好了

  

?  代碼大概長這個樣子

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#define ll long long
using namespace std;
const int N=4e5+10,TOP=20;
const ll inf=1LL<<60;
struct xxx{
    int y,nxt,id,dis;
}a[N*2];
struct Data{
    int node;
    ll dis;
    Data(){}
    Data(int node1,ll dis1){node=node1; dis=dis1;}
    friend bool operator < (Data x,Data y){return x.dis>y.dis;}
};
priority_queue<Data> q;
queue<int> q1;
vector<int> pre[N];
int lis[N];
int h[N],f[N][TOP+1],dep[N];
ll dis[N];
int vis[N],d[N],sz[N];
int n,m,tot,S;
void add(int x,int y,int dis,int id){a[++tot].y=y; a[tot].nxt=h[x]; h[x]=tot; a[tot].id=id; a[tot].dis=dis;}
void print(vector<int> x){
    for (int i=0;i<x.size();++i) printf("%d ",x[i]); printf("\n");
}
void dij(){
    int u,v;
    while (!q.empty()) q.pop();
    for (int i=1;i<=n;++i) dis[i]=inf,vis[i]=false;
    dis[S]=0;
    q.push(Data(S,dis[S]));
    while (!q.empty()){
        v=q.top().node; q.pop();
        if (vis[v]) continue;
        vis[v]=1;
        for (int i=h[v];i!=-1;i=a[i].nxt){
            u=a[i].y;
            if (vis[u]) continue;
            if (dis[u]>dis[v]+a[i].dis){
                dis[u]=dis[v]+a[i].dis;
                q.push(Data(u,dis[u]));
            }
        }
    }
    for (int x=1;x<=n;++x){
        for (int i=h[x];i!=-1;i=a[i].nxt){
            u=a[i].y;
            if (dis[u]==dis[x]+a[i].dis){
                pre[u].push_back(a[i].id+n);
                pre[a[i].id+n].push_back(x);
                ++d[a[i].id+n];
                ++d[x];
            }
        }
    }
}
int get_lca(int x,int y){
    if (!x||!y) return x+y;
    if (dep[x]<dep[y]) swap(x,y);   
    for (int i=TOP;i>=0;--i)
        if (dep[f[x][i]]>=dep[y]) x=f[x][i];
    if (x==y) return x;
    for (int i=TOP;i>=0;--i)
        if (f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
    return f[x][0];
}
void topo(int n){
    int u,v;
    while (!q1.empty()) q1.pop();
    for (int i=1;i<=n;++i)
        if (d[i]==0) q1.push(i);
    lis[0]=0;
    while (!q1.empty()){
        v=q1.front(); q1.pop();
        lis[++lis[0]]=v;
        for (int i=0;i<pre[v].size();++i){
            u=pre[v][i];
            --d[u];
            if (!d[u]) q1.push(u);
        }
    }
}
void get_fa(int x){
    int lca,Sz=pre[x].size();
    if (Sz==0){
        f[x][0]=0;
    }
    else if (Sz==1)
        f[x][0]=pre[x][0];
    else if (Sz>=2){
        lca=get_lca(pre[x][0],pre[x][1]);
        for (int i=2;i<Sz;++i)
            lca=get_lca(lca,pre[x][i]);
        f[x][0]=lca;
    }
    for (int i=1;i<=TOP;++i) f[x][i]=f[f[x][i-1]][i-1];
    dep[x]=dep[f[x][0]]+1; 
    sz[x]=(x<=n);
}
void solve(){
    topo(n+m);
    for (int i=lis[0];i>=1;--i)
        get_fa(lis[i]);
    for (int i=1;i<=lis[0];++i)
        sz[f[lis[i]][0]]+=sz[lis[i]];
}

int main(){
#ifndef ONLINE_JUDGE
    freopen("a.in","r",stdin);
#endif
    int x,y,z;
    scanf("%d%d",&n,&m);
    memset(h,-1,sizeof(h));
    tot=0;
    for (int i=1;i<=m;++i){
        scanf("%d%d%d",&x,&y,&z);
        add(x,y,z,i);
        add(y,x,z,i);
    }
    S=1;
    dij();
    solve();
    //for (int i=1;i<=n+m;++i) printf("%d " ,f[i][0]); printf("\n");
    for (int i=1;i<=m;++i)
        printf("%d\n",sz[i+n]);
}

【codeforces gym】Increasing Costs