1. 程式人生 > >洛谷|P4281 [AHOI2008]緊急集合 / 聚會

洛谷|P4281 [AHOI2008]緊急集合 / 聚會

洛谷|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個遊戲幣。

輸入輸出樣例

輸入樣例#1:

6 4  
1 2  
2 3  
2 4 
4 5
5 6
4 5 6
6 3 1
2 4 4 
6 6 6

輸出樣例#1:

5 2
2 5
4 1
6 0

說明

提示:

40%的資料中N<=2000,M<=2000
100%的資料中,N<=500000,M<=500000

這道題巨難!!

過程

開始想的是求那三個點的LCA,結果果然WA了。

左哥

同為不過樣例的程式碼,怎麼我就一個點沒過呢(滑稽)

後來看了 這個大佬 的題解,過程在原文,結論是:

那個點是LCA(a,b),LCA(b,c),LCA(a,c)中深度最大的

花費是deep(a)+deep(b)+deep(c)−最

LCA的深度−最LCA的深度∗2(其實就是減a,b,c三個深度,因為有兩個LCA是一樣的)

“在樹上任選三點t1,t2,t3,LCA(t1,t2),LCA(t1,t3),LCA(t2,t3)中一定有兩個是相等的。”

然後,在洛谷上過了,一中oj上TLE兩個點嚶。

最後用了快讀,加了inline,都還過不了

Code

(這份程式碼沒用快讀)

#include<bits/stdc++.h>
using namespace std;

const int MAXN=500000*2+5;
int n,m;

struct tu{
    private:
        struct ed{
            int to,nex;
        } e[MAXN];
        int head[MAXN],newp,siz,root,H,f[MAXN][20];
        int depth[MAXN];
        bool bfsed;
        
    public:
        inline void clear(void){
            memset(e,0,sizeof(e));
            memset(head,0,sizeof(head));
            memset(f,0,sizeof(f));
            memset(depth,0,sizeof(depth));
            newp=0;
            siz=0;
            root=1;
            bfsed=0;
        }
        
        inline void vAdd(int p1,int p2){
            ++newp;
            e[newp].to=p2;
            e[newp].nex=head[p1];
            head[p1]=newp;
        }
        
        inline void resize(int s){
            siz=s;
            H=(int)(1.0*log(siz)/log(2)+0.5);
        }
        
        inline int size(void){
            return siz;
        }
        
        inline int lca(int p1,int p2){
            if(!bfsed){
                bfs();
            }
            
            if(depth[p1]<depth[p2]){
                swap(p1,p2);
            }
            
            for(int i=H;i>=0;--i){
                if(depth[f[p1][i]]>=depth[p2]){
                    p1=f[p1][i];
                }
            }
            
            if(p1==p2)return p1;
            
            for(int i=H;i>=0;--i){
                if(f[p1][i]!=f[p2][i]){
                    p1=f[p1][i];
                    p2=f[p2][i];
                }
            }
            return f[p1][0];
        }
        
        inline void solve(int x,int y,int z){
            int a,b,c;
            a=lca(x,y);
            b=lca(y,z);
            c=lca(x,z);
            int ans1,ans2;
            if(depth[a]>=depth[b] && depth[a]>=depth[c]){
                ans1=a;
            }
            
            else if(depth[b]>=depth[a] && depth[b]>=depth[c]){
                ans1=b;
            }
            
            else if(depth[c]>=depth[a] && depth[c]>=depth[b]){
                ans1=c;
            }
            int pt1=depth[x]-depth[a];
            int pt2=depth[y]-depth[b];
            int pt3=depth[z]-depth[c];
            ans2=pt1+pt2+pt3;
            printf("%d %d\n",ans1,ans2);
        }
        
        inline void bfs(void){
            queue<int> q;
            q.push(root);
            depth[root]=1;
            while(!q.empty()){
                int x=q.front();
                q.pop();
                for(int i=head[x];i;i=e[i].nex){
                    int y=e[i].to;
                    
                    if(depth[y])continue;
                    
                    depth[y]=depth[x]+1;
                    
                    f[y][0]=x;
                    
                    for(int j=1;j<=H;++j){
                        f[y][j]=f[f[y][j-1]][j-1];
                    }
                    
                    q.push(y);
                }
            }
            bfsed=1;
        }
        
        
};

tu a;

int main(void){
    scanf("%d%d",&n,&m);
    a.clear();
    a.resize(n);
    for(int i=1;i<n;++i){
        int p1,p2;
        scanf("%d%d",&p1,&p2);
        a.vAdd(p1,p2);
        a.vAdd(p2,p1);
    }
    
    for(int i=1;i<=m;++i){
        int keke,kaka,waiwai;
        scanf("%d%d%d",&keke,&kaka,&waiwai);
        a.solve(keke,kaka,waiwai);
    }
    
    return 0;
}