1. 程式人生 > >CodeForces 455C (貪心,並查集)

CodeForces 455C (貪心,並查集)

題意:
給出一個n個點m條邊的森林,q次詢問,第一種詢問要求輸出一個點所在樹的直徑,第二種詢問要求合併兩個點所在的樹。


思路:
先將初始的森林中各個樹的直徑求出來,然後用並查集維護。兩樹合併時,設直徑分別為len1,len2,新樹直徑為max(len1,len2,(len1/2)+(len2/2)+(len1%2)+(len2%2)+1),即兩顆舊樹的直徑,兩顆舊樹直徑的一半向上取整加一,中的較大值。
優化上可以用並查集路徑壓縮+啟發式合併,輸入掛。


程式碼:

#include <iostream>
#include <iomanip>
#include <algorithm>
#include <cstring>
#include <cctype>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <ctime>
#include <map>
#include <list>
#include <set>
#include <stack>
#include <queue>
#include <string>
#include <sstream>
#define pb push_back
#define X first
#define Y second
#define ALL(x) x.begin(),x.end()
#define INS(x) inserter(x,x.begin())
#define pii pair<int,int>
#define qclear(a) while(!a.empty())a.pop();
#define lowbit(x) (x&-x)
//#define sd(n) scanf("%d",&n)
#define sdd(n,m) scanf("%d%d",&n,&m)
#define sddd(n,m,k) scanf("%d%d%d",&n,&m,&k)
#define mst(a,b) memset(a,b,sizeof(a))
#define cout3(x,y,z) cout<<x<<" "<<y<<" "<<z<<endl
#define cout2(x,y) cout<<x<<" "<<y<<endl
#define cout1(x) cout<<x<<endl
#define IOS std::ios::sync_with_stdio(false)
#define SRAND srand((unsigned int)(time(0)))
typedef long long ll;
typedef unsigned long long ull;
typedef unsigned int uint;
using namespace std;
const double PI=acos(-1.0);
const int INF=0x3f3f3f3f;
const ll mod=998244353;
const double eps=1e-8;
const int maxn=300005;
const int maxm=10005;
template<class T>
inline bool sd(T &ret){
    char c;
    int sgn;
    if(c=getchar(),c==EOF)return 0;
    while(c!='-'&&(c<'0'||c>'9'))c=getchar();
    sgn=(c=='-')?-1:1;
    ret=(c=='-')?0:(c-'0');
    while(c=getchar(),c>='0'&&c<='9')ret=ret*10+(c-'0');
    ret*=sgn;
    return 1;
}
inline void out(int x){
    if(x>9)out(x/10);
    putchar(x%10+'0');
}


int n,m,q;
vector<int>maps[maxn];
int fa[maxn];
int rk[maxn];
inline void init(){
    for(int i=0;i<=n;i++){
        fa[i]=i;
        rk[i]=1;
    }
}
inline int findfa(int x){
    return fa[x]==x?x:fa[x]=findfa(fa[x]);
}
inline void meg(int a,int b){
    int f1,f2;
    f1=findfa(a);
    f2=findfa(b);
    if(rk[f1]<rk[f2]){
        fa[f1]=f2;
        rk[f2]+=rk[f1];
    }else{
        fa[f2]=f1;
        rk[f1]+=rk[f2];
    }
    return ;
}
int lens[maxn];
bool vis[maxn];
int maxlen=0;
int mark=-1;
inline void dfs(int u,int d){
    vis[u]=1;
    if(d>maxlen){
        maxlen=d;
        mark=u;
    }
    for(int i=0;i<maps[u].size();i++){
        int v=maps[u][i];
        if(!vis[v]){
            dfs(v,d+1);
        }
    }
    vis[u]=0;
}
inline void callens(int now){
    maxlen=0;
    mark=-1;
    dfs(now,0);
    dfs(mark,0);
    lens[now]=maxlen;
}
void solve() {
    sd(n);
    sd(m);
    sd(q);
    init();
    for(int i=0;i<m;i++){
        int u,v;
        sd(u);
        sd(v);
        maps[u].pb(v);
        maps[v].pb(u);
        meg(u,v);
    }
    mst(lens,0);
    mst(vis,0);
    for(int i=1;i<=n;i++){
        int now=findfa(i);
        if(lens[now]==0){
            callens(now);
        }
    }
    for(int qq=0;qq<q;qq++){
        int op,u,v;
        sd(op);
        if(op==1){
            sd(u);
            out(lens[findfa(u)]);
            putchar('\n');
        }else{
            sd(u);
            sd(v);
            if(findfa(u)==findfa(v))continue;
            int len1,len2,len3;
            len1=lens[findfa(u)];
            len2=lens[findfa(v)];
            len3=(len1>>1)+(len2>>1)+(len1&1)+(len2&1)+1;
            meg(u,v);
            lens[findfa(u)]=max(len1,max(len2,len3));
        }
    }
    return ;
}
int main() {
#ifdef LOCAL
    freopen("in.txt","r",stdin);
//    freopen("out.txt","w",stdout);
#else
    //    freopen("","r",stdin);
    //    freopen("","w",stdout);
#endif
    solve();
    return 0;
}