Educational Codeforces Round 46 (Rated for Div. 2)E. We Need More Bosses

题目链接:E. We Need More Bosses

题解:tarjan有向图缩点之后求树的直径就是答案:应为在同一个强联通里的边就不是必须边,参考了这个

 

#include<bits/stdc++.h>
#include<set>
#include<cstdio>
#include<iomanip>
#include<iostream>
#include<string>
#include<cstring>
#include<algorithm>
#define pb push_back
#define mk make_pair
#define ll long long
#define fi first
#define se second
#define PI 3.14159265
#define ls l,m,rt<<1
#define rs m+1,r,rt<<1|1
#define eps 1e-7
#define pii pair<int,int>
#define pll pair<ll,ll>
typedef unsigned long long ull;
const int mod=998244353;
const ll inf=0x3f3f3f3f3f3f3f;
const int maxn=1e6+5;
using namespace std;
int n,m;
vector<int>g[maxn],G[maxn];
int dnf[maxn],low[maxn],ind,scc[maxn],scc_cnt,s[maxn],head,d[maxn];
void tarjan(int v,int f)
{
    dnf[v]=low[v]=++ind;
    s[++head]=v;
    for(int to :g[v])
    {
        if(f==to)continue;
        if(!dnf[to])
        {
            tarjan(to,v);
            low[v]=min(low[v],low[to]);
        }
        else low[v]=min(low[v],dnf[to]);
    }
    if(low[v]==dnf[v])
    {
        scc[v]=++scc_cnt;
        while(s[head]!=v)scc[s[head--]]=scc_cnt;
        head--;
    }
}
void dfs(int v,int f,int dep)
{
    d[v]=dep;
    for(int to:G[v])
    {
        if(to!=f)dfs(to,v,dep+1);
    }
}
int main()
{
    /* ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);*/
    //cin>>n>>m;
    scanf("%d %d",&n,&m);
    //cout<<d[(int)1e9]<<endl;
    for(int i=0;i<m;i++)
    {
        int x,y;
        //cin>>x>>y;
        scanf("%d %d",&x,&y);
        g[x].pb(y);g[y].pb(x);
    }
    tarjan(1,0); //cout<<"SSS"<<endl;
    for(int i=1;i<=n;i++)
    {
        for(int to:g[i])
        {
            if(scc[i]!=scc[to])
            {
                G[scc[i]].pb(scc[to]);
            }
        }
    }
    dfs(1,0,0);
    int tmp=0,s;
    for(int i=1;i<=scc_cnt;i++)
    {
        if(d[i]>tmp)s=i,tmp=d[i];
    }
    for(int i=0;i<=scc_cnt;i++)d[i]=0;
    dfs(s,0,0);
    int ans=0;
    for(int i=1;i<=scc_cnt;i++)
    {
        ans=max(d[i],ans);
    }
    printf("%d\n",ans);
    return 0;
}

有个相似的题

题目链接:E. Anton and Tree

题意:就是一次操作选中一个点并把所有到这个点最短路经过是颜色相同的点颜色反转,问至少几次操作把所有的颜色变为相同的点

题解:把相同颜色的相邻的点缩成一个点然后求树的直径,答案时(直径+1)/2

#include<bits/stdc++.h>
#include<set>
#include<cstdio>
#include<iomanip>
#include<iostream>
#include<string>
#include<cstring>
#include<algorithm>
#define pb push_back
#define mk make_pair
#define ll long long
#define fi first
#define se second
#define PI 3.14159265
#define ls l,m,rt<<1
#define rs m+1,r,rt<<1|1
#define eps 1e-7
#define pii pair<int,int>
#define pll pair<ll,ll>
typedef unsigned long long ull;
const int mod=998244353;
const ll inf=0x3f3f3f3f3f3f3f;
const int maxn=1e6+5;
using namespace std;
int n,m;
vector<int>g[maxn],G[maxn];
int c[maxn];
int sc[maxn],cnt;
int dis[maxn];
bool vis[maxn];
void dfs(int v,int f,int ind,int cm)
{
    sc[v]=ind;
    vis[v]=true;
    for(int to:g[v])
    {
        if(to==f)continue;
        if(!vis[to]&&c[to]==cm)dfs(to,v,ind,cm);
    }
}
void dfs1(int v,int f,int d)
{
    dis[v]=d;
    for(int to:G[v])
    {
        if(to==f)continue;
            dfs1(to,v,d+1);
    }
}
int main()
{
     ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    cin>>n;
    for(int i=1;i<=n;i++)cin>>c[i];
    for(int i=0;i<n-1;i++)
    {
        int x,y;
        cin>>x>>y;
        g[x].pb(y);g[y].pb(x);
    }
    for(int i=1;i<=n;i++)
    {
        if(!vis[i]) dfs(i,0,++cnt,c[i]);
    }
    for(int i=1;i<=n;i++)
    {
        for(int to:g[i])
        {
            if(sc[to]!=sc[i])
            {
                G[sc[i]].pb(sc[to]);
            }
        }
    }
    dfs1(1,0,0);int tmp=0,s;
    for(int i=1;i<=cnt;i++)
    {
        if(dis[i]>tmp)s=i,tmp=dis[i];
    }
    memset(dis,0,sizeof(dis));
    dfs1(s,0,0);
    int ans=0;
    for(int i=1;i<=cnt;i++)
    {
        ans=max(ans,dis[i]);
    }
    cout<<(ans+1)/2<<endl;
    return 0;
}

  

 

posted @ 2018-07-11 17:37  lhclqslove  阅读(178)  评论(0编辑  收藏  举报