[AHOI2008] 紧急集合
Description
歡樂島上有個非常好玩的游戲,叫做“緊急集合”。在島上分散有N個等待點,有N-1條道路連接著它們,每一條道路都連接某兩個等待點,且通過這些道路可以走遍所有的等待點,通過道路從一個點到另一個點要花費一個游戲幣。
參加游戲的人三人一組,開始的時候,所有人員均任意分散在各個等待點上(每個點同時允許多個人等待),每個人均帶有足夠多的游戲幣(用于支付使用道路的花費)、地圖(標明等待點之間道路連接的情況)以及對話機(用于和同組的成員聯系)。當集合號吹響后,每組成員之間迅速聯系,了解到自己組所有成員所在的等待點后,迅速在N個等待點中確定一個集結點,組內所有成員將在該集合點集合,集合所用花費最少的組將是游戲的贏家。
小可可和他的朋友邀請你一起參加這個游戲,由你來選擇集合點,聰明的你能夠完成這個任務,幫助小可可贏得游戲嗎?
Input
第一行兩個正整數N和M(N<=500000,M<=500000),之間用一個空格隔開。分別表示等待點的個數(等待點也從1到N進行編號)和獲獎所需要完成集合的次數。 隨后有N-1行,每行用兩個正整數A和B,之間用一個空格隔開,表示編號為A和編號為B的等待點之間有一條路。 接著還有M行,每行用三個正整數表示某次集合前小可可、小可可的朋友以及你所在等待點的編號。
Output
一共有M行,每行兩個數P,C,用一個空格隔開。其中第i行表示第i次集合點選擇在編號為P的等待點,集合總共的花費是C個游戲幣。
說明
\(100\%\)的數據中,\(N\leq500000\),\(M\leq500000\)
Solution
這題就差在說明里寫上“這是一道性質題,推出來性質你就能A,不然就乖乖打暴力吧!”
首先能觀察到的是這三個點之間兩兩的 \(lca\) 只能是兩個點或更少
也就是說,必定有至少兩對點是同一個 \(lca\)
這啟發我們從 \(lca\) 入手推性質。
手玩幾組數據發現答案就是三個 \(lca\) 中深度較淺的那個。
所以直接求出這三個 \(lca\) 然后暴力求距離即可
但是正解好像是再推一下式子,發現無論如何 \[ans=dep[x]+dep[y]+dep[z]-dep[lca(x,y)]-dep[lca(x,z)]-dep[lca(y,z)]\].
求距離都不用,直接減就行了。
#include<cstdio> #include<cctype> #define N 500005 #define min(A,B) ((A)<(B)?(A):(B)) #define swap(A,B) ((A)^=(B)^=(A)^=(B))int dfn[N],top[N],d[N]; int n,m,cnt,tot,sum[N<<2]; int fa[N],sze[N],son[N],head[N];struct Edge{int to,nxt; }edge[N<<1];void add(int x,int y){edge[++cnt].to=y;edge[cnt].nxt=head[x];head[x]=cnt; }int getint(){int x=0;char ch=getchar();while(!isdigit(ch)) ch=getchar();while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();return x; }void first_dfs(int now){sze[now]=1;for(int i=head[now];i;i=edge[i].nxt){int to=edge[i].to;if(sze[to])continue;fa[to]=now;d[to]=d[now]+1;first_dfs(to);sze[now]+=sze[to];if(sze[to]>sze[son[now]])son[now]=to;} }void second_dfs(int now,int low){top[now]=low;dfn[now]=++tot;if(son[now])second_dfs(son[now],low);for(int i=head[now];i;i=edge[i].nxt){int to=edge[i].to;if(to==fa[now] or to==son[now])continue;second_dfs(to,to);} }int query(int cur,int l,int r,int ql,int qr){if(ql<=l and r<=qr)return r-l+1;int mid=l+r>>1,ans=0;if(ql<=mid)ans+=query(cur<<1,l,mid,ql,qr);if(mid<qr)ans+=query(cur<<1|1,mid+1,r,ql,qr);return ans; }int lca(int x,int y){while(top[x]!=top[y]){if(d[top[x]]<d[top[y]])swap(x,y);x=fa[top[x]];}if(d[x]<d[y])swap(x,y);return y; }int ask(int x,int y){int ans=0;while(top[x]!=top[y]){if(d[top[x]]<d[top[y]])swap(x,y);ans+=query(1,1,n,dfn[top[x]],dfn[x]);x=fa[top[x]];}if(d[x]<d[y])swap(x,y);if(x!=y)ans+=query(1,1,n,dfn[y]+1,dfn[x]);return ans; }signed main(){n=getint(),m=getint();for(int i=1;i<n;i++){int x=getint(),y=getint();add(x,y);add(y,x);}d[1]=1; first_dfs(1);second_dfs(1,1);while(m--){int a=getint(),b=getint(),c=getint();int x=lca(a,b),y=lca(a,c),z=lca(b,c);int ans=d[a]+d[b]+d[c]-d[x]-d[y]-d[z];if(d[x]>=d[y] and d[x]>=d[z])printf("%d %d\n",x,ans);else if(d[y]>=d[x] and d[y]>=d[z])printf("%d %d\n",y,ans);else if(d[z]>=d[x] and d[z]>=d[y])printf("%d %d\n",z,ans);/*int a=getint(),b=getint(),c=getint();int x=lca(a,b);int y=lca(a,c);if(x!=y){if(d[x]<d[y]){int ans=d[a]+d[c]-2*d[y];ans+=ask(b,y);printf("%d %d\n",y,ans);} else{int ans=d[a]+d[b]-2*d[x];ans+=ask(c,x);printf("%d %d\n",x,ans);}} else{int z=lca(b,c);if(z==x){int ans=d[a]+d[b]+d[c]-3*d[z];printf("%d %d\n",z,ans);} else{if(d[x]<d[z]){int ans=d[b]+d[c]-2*d[z];ans+=ask(a,z);printf("%d %d\n",z,ans);} else{int ans=d[a]+d[b]-2*d[x];ans+=ask(c,x);printf("%d %d\n",x,ans);}}}*/}return 0; }轉載于:https://www.cnblogs.com/YoungNeal/p/9161763.html
超強干貨來襲 云風專訪:近40年碼齡,通宵達旦的技術人生總結
以上是生活随笔為你收集整理的[AHOI2008] 紧急集合的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: setInterval(callback
- 下一篇: Git服务器搭建