zoukankan      html  css  js  c++  java
  • 洛谷P4281[AHOI2008]紧急集合 / 聚会

    题目描述

    欢乐岛上有个非常好玩的游戏,叫做“紧急集合”。在岛上分散有N个等待点,有N-1条道路连接着它们,每一条道路都连接某两个等待点,且通过这些道路可以走遍所有的等待点,通过道路从一个点到另一个点要花费一个游戏币。

    参加游戏的人三人一组,开始的时候,所有人员均任意分散在各个等待点上(每个点同时允许多个人等待),每个人均带有足够多的游戏币(用于支付使用道路的花费)、地图(标明等待点之间道路连接的情况)以及对话机(用于和同组的成员联系)。当集合号吹响后,每组成员之间迅速联系,了解到自己组所有成员所在的等待点后,迅速在N个等待点中确定一个集结点,组内所有成员将在该集合点集合,集合所用花费最少的组将是游戏的赢家。

    小可可和他的朋友邀请你一起参加这个游戏,由你来选择集合点,聪明的你能够完成这个任务,帮助小可可赢得游戏吗?

    输入格式

    第一行两个正整数N和M(N<=500000,M<=500000),之间用一个空格隔开。分别表示等待点的个数(等待点也从1到N进行编号)和获奖所需要完成集合的次数。 随后有N-1行,每行用两个正整数A和B,之间用一个空格隔开,表示编号为A和编号为B的等待点之间有一条路。 接着还有M行,每行用三个正整数表示某次集合前小可可、小可可的朋友以及你所在等待点的编号。

    输出格式

    一共有M行,每行两个数P,C,用一个空格隔开。其中第i行表示第i次集合点选择在编号为P的等待点,集合总共的花费是C个游戏币。

    说明/提示

    提示:

    40%的数据中N<=2000,M<=2000
    100%的数据中,N<=500000,M<=500000

    主要思路:

    1.对于40%的数据,我当时看了一眼,哇,这个不就是三个点分别组成的三个lca中的一个点就是答案,然后15分钟打了个lca,但在算答案的时候,竟然憨憨的把所有点扫了一遍来算,后来发现自己太菜了,但上述做法就是40分的做法(白白丢了60分)。。。这里把代码也贴这里吧

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    using namespace std;
    #define maxn 500010
    #define ll long long
    #define IL inline
    #define clear(a) memset(a,0,sizeof a)
    
    int n,m,tot,t,num,ans;
    int first[maxn],deep[maxn],fa[maxn][22],cnt[maxn];
    struct edge{
        int nextx,to;
    }e[maxn<<1];
    
    void add(int u,int v){
        tot++;
        e[tot].nextx=first[u];
        first[u]=tot;
        e[tot].to=v;
    }
    
    void dfs_lca(int u,int f,int depth){
        deep[u]=depth,fa[u][0]=f;
        for(int i=first[u];i;i=e[i].nextx){
            int v=e[i].to;
            if(v==f)continue;
            fa[v][0]=u;
            for(int j=1;j<=t;j++)
                fa[v][j]=fa[fa[v][j-1]][j-1];
            dfs_lca(v,u,depth+1);
        }
    }
    
    int get_lca(int x,int y){
        if(deep[x]<deep[y])swap(x,y);
        for(int i=t;i>=0;i--)
            if(deep[fa[x][i]]>=deep[y])
                x=fa[x][i];
        if(x==y)return x;
        for(int i=t;i>=0;i--)
            if(fa[x][i]!=fa[y][i])
                x=fa[x][i],y=fa[y][i];
        return fa[x][0];
    }
    
    int get_dis(int x,int y){
        return deep[x]+deep[y]-2*deep[get_lca(x,y)];
    }
    
    int main(){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n-1;i++){
            int a,b;
            scanf("%d%d",&a,&b);
            add(a,b),add(b,a);
        }
        t=log2(n);
        dfs_lca(1,1,1);
        for(int i=1;i<=m;i++){
            ans=0,clear(cnt);
            int a,b,c;
            scanf("%d%d%d",&a,&b,&c);
            int l_ab=get_lca(a,b),l_ac=get_lca(a,c),l_bc=get_lca(c,b);
            ans+=(deep[a]+deep[b])-2*deep[l_ab];
            ans+=(deep[a]+deep[c])-2*deep[l_ac];
            ans+=(deep[c]+deep[b])-2*deep[l_bc];
            ans/=2;
            for(int j=1;j<=n;j++){
                int num=0;
                num+=(get_dis(a,j)+get_dis(b,j)+get_dis(c,j));
                if(num==ans){
                    printf("%d %d
    ",j,ans);
                    break;
                }
            }
        }
        return 0;
    }

    2.100分的做法就是上文说到的,经过一系列的手玩,我们发现那三个lca,其实有两个lca是相同的,而答案就是那个与另外两个不同的那一个(手玩出奇迹),这样的话,我们就不需要每次扫一遍了,三个if就可以了,详见代码:

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    using namespace std;
    #define maxn 500010
    #define ll long long
    #define IL inline
    #define clear(a) memset(a,0,sizeof a)
    
    int n,m,tot,t,num,ans;
    int first[maxn],deep[maxn],fa[maxn][22],cnt[maxn];
    struct edge{
        int nextx,to;
    }e[maxn<<1];
    
    IL void read(int &x){
        x=0;char ch=getchar();int f=1;
        while(ch<'0'||ch>'9'){if(ch=='-')f=-f;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0',ch=getchar();}x*=f;
    }
    
    IL void add(int u,int v){
        tot++;
        e[tot].nextx=first[u];
        first[u]=tot;
        e[tot].to=v;
    }
    
    void dfs_lca(int u,int f,int depth){
        deep[u]=depth,fa[u][0]=f;
        for(int i=first[u];i;i=e[i].nextx){
            int v=e[i].to;
            if(v==f)continue;
            fa[v][0]=u;
            for(int j=1;j<=t;j++)
                fa[v][j]=fa[fa[v][j-1]][j-1];
            dfs_lca(v,u,depth+1);
        }
    }
    
    IL int get_lca(int x,int y){
        if(deep[x]<deep[y])swap(x,y);
        for(int i=t;i>=0;i--)
            if(deep[fa[x][i]]>=deep[y])
                x=fa[x][i];
        if(x==y)return x;
        for(int i=t;i>=0;i--)
            if(fa[x][i]!=fa[y][i])
                x=fa[x][i],y=fa[y][i];
        return fa[x][0];
    }
    
    int get_dis(int x,int y){
        return deep[x]+deep[y]-2*deep[get_lca(x,y)];
    }
    
    int main(){
        read(n),read(m);
        for(int i=1;i<=n-1;i++){
            int a,b;
            read(a),read(b);
            add(a,b),add(b,a);
        }
        t=log2(n);
        dfs_lca(1,1,1);
        for(int i=1;i<=m;i++){
            ans=0,clear(cnt);
            int a,b,c;
            read(a),read(b),read(c);
            int l_ab=get_lca(a,b),l_ac=get_lca(a,c),l_bc=get_lca(c,b);
            ans+=(deep[a]+deep[b])-2*deep[l_ab];
            ans+=(deep[a]+deep[c])-2*deep[l_ac];
            ans+=(deep[c]+deep[b])-2*deep[l_bc];
            ans/=2;
            if(l_ab==l_bc){
                printf("%d %d
    ",l_ac,ans);
                continue;
            }
            else if(l_ab==l_ac){
                printf("%d %d
    ",l_bc,ans);
                continue;
            }
            else if(l_bc==l_ac){
                printf("%d %d
    ",l_ab,ans);
                continue;
            }
        }
        return 0;
    }
  • 相关阅读:
    在日本被禁止的コンプガチャ設計
    Starling常见问题解决办法
    Flixel引擎学习笔记
    SQLSERVER中修复状态为Suspect的数据库
    T4 (Text Template Transformation Toolkit)实现简单实体代码生成
    创建Linking Server in SQL SERVER 2008
    Linq to Sql 与Linq to Entities 生成的SQL Script与分页实现
    Linq to Entity 的T4 模板生成代码
    在VisualStudio2008 SP1中调试.net framework 源代码
    使用HttpModules实现Asp.net离线应用程序
  • 原文地址:https://www.cnblogs.com/KGW-/p/11834956.html
Copyright © 2011-2022 走看看