tarjan

一、缩点

题目链接

https://www.luogu.com.cn/problem/P3387

题目大意

image

题目思路

缩点 + 拓扑序 + dp

代码

#include<iostream>
#include<queue>
#include<cstring>
#include<algorithm>
#include<set>
#define pi pair<int,int>
const int N = 1e4 + 5,M = 1e5 + 5;
using namespace std;
int n,m;
int h[N],ne[M],e[M],idx;
int h1[N],ne1[M],e1[M],idx1;
int stk[N],in_stk[N],top;
int dfn[N],low[N],fa[N],timestamp;
int a[N];
int din[N];
pi edge[M];
int dp[N];
set<pi>s;
void add(int a,int b){
    e[idx] = b;
    ne[idx] = h[a];
    h[a] = idx++;
}
void add1(int a,int b){
    e1[idx1] = b;
    ne1[idx1] = h1[a];
    h1[a] = idx1++;
}
void tarjan(int x){
    dfn[x] = low[x] = ++ timestamp;
    stk[++top] = x;in_stk[x] = 1;
    for(int i = h[x];~i;i = ne[i]){
        int y = e[i];
        if(!dfn[y]) {
            tarjan(y);
            low[x] = min(low[x],low[y]);
        }else if(in_stk[y]){
            low[x] = min(low[x],dfn[y]);
        }
    }
    if(dfn[x] == low[x]){
        int y;
        do{
            y = stk[top--];in_stk[y] = 0;
            fa[y] = x;
            if(x == y) break;
            a[x] += a[y];
        }while(true);
    }
}
int topsort(){
    queue<int>q;
    int ans = 0;
    for(int i = 1;i <= n;++i){
        if(fa[i] == i && din[i] == 0){
            q.push(i);
            dp[i] = a[i];
            ans = max(ans,dp[i]);
        }
    }
    while(!q.empty()){
        int u = q.front();q.pop();
        for(int i = h1[u];~i;i = ne1[i]){
            int v = e1[i];
            dp[v] = max(dp[v],dp[u] + a[v]);
            ans = max(ans,dp[v]);
            --din[v];
            if(din[v] == 0) q.push(v);
        }
    }
    return ans;
}
int main()
{
    scanf("%d%d",&n,&m);
    memset(h,-1,sizeof(h));
    for(int i = 1;i <= n;++i) scanf("%d",&a[i]);
    for(int i = 1;i <= m;++i){
        int x,y;scanf("%d%d",&x,&y);add(x,y);
        edge[i] = {x,y};
    }
    for(int i = 1;i <= n;++i){
        if(!dfn[i]) tarjan(i);
    }
    memset(h1,-1,sizeof(h1));
    for(int i = 1;i <= m;++i){
        int x = fa[edge[i].first],y = fa[edge[i].second];
        if(x != y && !s.count({x,y})){
            add1(x,y);
            ++din[y];
            s.insert({x,y});
        }
    }
    printf("%d",topsort());
    return 0;
}

二、求LCA

题目链接

https://www.luogu.com.cn/problem/P3379

题目大意

image

代码

#include<iostream>
#include<vector>
#define pi pair<int,int>
const int N = 5e5 + 5;
using namespace std;
int n,m,root;
int fa[N];
int vis[N],ans[N];
vector<int>g[N];
vector<pi>query[N];
int find(int x){
    if(x == fa[x]) return x;
    return fa[x] = find(fa[x]);
}
void tarjan(int u){
    vis[u] = 1;
    for(auto v:g[u]){
        if(!vis[v]){
            tarjan(v);
            fa[v] = u;
        }
    }
    for(auto q:query[u]){
        int v = q.first,i = q.second;
        if(vis[v]) ans[i] = find(v);
    }
}
int main()
{
    scanf("%d%d%d",&n,&m,&root);
    for(int i = 1;i <= n - 1;++i){
        int a,b;scanf("%d%d",&a,&b);
        g[a].push_back(b);g[b].push_back(a);
    }
    for(int i = 1;i <= m;++i){
        int a,b;scanf("%d%d",&a,&b);
        query[a].emplace_back(b,i);
        query[b].emplace_back(a,i);
    }
    for(int i = 0;i <= n;++i) fa[i] = i;
    tarjan(root);
    for(int i = 1;i <= m;++i){
        printf("%d\n",ans[i]);
    }
    return 0;
}
posted @ 2024-04-16 09:32  gebeng  阅读(10)  评论(0)    收藏  举报