• CF418D Big Problems for Organizers


    CF418D Big Problems for Organizers


    题意:一个树,每次给两个点(x,y),询问(max[min(dist(x,i),dist(y,i))])

    神仙题鸭orz。

    先抠出树的直径,然后答案只会是:直径端点的答案,或者这两个点中间的答案。

    然后大力分类讨论即可。。。真不想写了。。

    #include<bits/stdc++.h>
    #define il inline
    #define vd void
    typedef long long ll;
    il int gi(){
        int x=0,f=1;
        char ch=getchar();
        while(!isdigit(ch)){
            if(ch=='-')f=-1;
            ch=getchar();
        }
        while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
        return x*f;
    }
    int fir[100010],nxt[200010],dis[200010],id;
    il vd link(int a,int b){nxt[++id]=fir[a],fir[a]=id,dis[id]=b;}
    int dist[100010],lst[100010];
    il vd BFS(int S){
        static bool vis[100010];
        static int que[100010];
        int hd=0,tl=0;
        memset(vis,0,sizeof vis);
        vis[S]=1;que[tl++]=S;lst[S]=0;
        while(hd^tl){
            int x=que[hd];
            for(int i=fir[x];i;i=nxt[i])
                if(!vis[dis[i]])vis[dis[i]]=1,que[tl++]=dis[i],dist[dis[i]]=dist[x]+1,lst[dis[i]]=x;
            ++hd;
        }
    }
    int s[100010],tot,f[100010],w[100010],st1[17][100010],st2[17][100010],lg[100010],tp[100010],dst[100010];
    il vd dfs(int x,int A=-1,int B=-1){
        for(int i=fir[x];i;i=nxt[i]){
            if(dis[i]==A||dis[i]==B)continue;
            tp[dis[i]]=tp[x];
            dst[dis[i]]=dst[x]+1;
            dfs(dis[i],x);
            f[x]=std::max(f[x],f[dis[i]]+1);
        }
    }
    il int query(int st[][100010],int l,int r){
        if(l>r)return -1e9;
        return std::max(st[lg[r-l+1]][l],st[lg[r-l+1]][r-(1<<lg[r-l+1])+1]);
    }
    int main(){
    #ifndef ONLINE_JUDGE
        freopen("418d.in","r",stdin);
        freopen("418d.out","w",stdout);
    #endif
        int n=gi(),a,b,A=1,B=1;
        for(int i=1;i<n;++i)a=gi(),b=gi(),link(a,b),link(b,a);
        BFS(1);for(int i=1;i<=n;++i)if(dist[i]>dist[A])A=i;
        BFS(A);for(int i=1;i<=n;++i)if(dist[i]>dist[B])B=i;
        for(int i=B;i;i=lst[i])s[++tot]=i;
        for(int i=1;i<=tot;++i)tp[s[i]]=i,dfs(s[i],s[i-1],s[i+1]),w[i]=f[s[i]],st1[0][i]=f[s[i]]+i,st2[0][i]=f[s[i]]-i;
        for(int i=2;i<=n;++i)lg[i]=lg[i>>1]+1;
        for(int i=1;i<=lg[tot];++i)
            for(int j=1;j+(1<<i)-1<=tot;++j){
                st1[i][j]=std::max(st1[i-1][j],st1[i-1][j+(1<<i-1)]);
                st2[i][j]=std::max(st2[i-1][j],st2[i-1][j+(1<<i-1)]);
            }
        int m=gi(),ans,mid;
        while(m--){
            a=gi(),b=gi();
            if(tp[a]>tp[b])std::swap(a,b);
            mid=std::min(tp[b],std::max(tp[a],(dst[b]-dst[a]+tp[b]-tp[a])/2+tp[a]));
            int len=dst[a]+dst[b]+tp[b]-tp[a];
            if(tp[a]!=tp[b]){
                ans=std::max(std::min(dst[a]+tp[a]-1,dst[b]+tp[b]-1),std::min(dst[a]+tot-tp[a],dst[b]+tot-tp[b]));
                if(dst[a]*2<len&&dst[b]*2<len){
                    ans=std::max(ans,query(st1,tp[a]+1,mid)-tp[a]+dst[a]);
                    if(mid!=tp[b])ans=std::max(ans,query(st2,mid+1,tp[b]-1)+tp[b]+dst[b]);
                }
                else{
                    if(mid==tp[a])ans=std::max(ans,std::max((len+1)/2,query(st2,tp[a]+1,tp[b])+tp[b]+dst[b]));
                    else ans=std::max(ans,std::max((len+1)/2,query(st1,tp[a],tp[b]-1)-tp[a]+dst[a]));
                }
            }else ans=std::max(std::min(dst[a],dst[b])+tp[a]-1,std::min(dst[a],dst[b])+tot-tp[a]);
            printf("%d
    ",ans);
        }
        return 0;
    }
    
    
  • 相关阅读:
    联表查询用on和where的区别
    了解触发器
    QUIC协议,了解
    SQL Mode
    redis持久化
    Kali Linux渗透测试实战 1.2 环境安装及初始化
    电容降压
    单火取电
    大整数的因子
    最大公约数
  • 原文地址:https://www.cnblogs.com/xzz_233/p/9762746.html
Copyright © 2020-2023  润新知