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

[AHOI2008] 紧急集合相关推荐

  1. P4281 [AHOI2008]紧急集合 / 聚会

    P4281 [AHOI2008]紧急集合 / 聚会 军训完.发现我自己连lca版都不会了 然后就强行写了这个题 然后卡了两天的原因就是计算距离写错了 #include<cstdio> #i ...

  2. 洛谷 P4281 [AHOI2008]紧急集合 / 聚会(树上倍增 LCA)

    [AHOI2008]紧急集合 / 聚会 题目描述 欢乐岛上有个非常好玩的游戏,叫做"紧急集合".在岛上分散有 n n n 个等待点,有 n − 1 n-1 n−1 条道路连接着它们 ...

  3. P4281 [AHOI2008]紧急集合 / 聚会(LCA做法)

    题目描述 欢乐岛上有个非常好玩的游戏,叫做"紧急集合".在岛上分散有N个等待点,有N-1条道路连接着它们,每一条道路都连接某两个等待点,且通过这些道路可以走遍所有的等待点,通过道路 ...

  4. 洛谷· [AHOI2008]紧急集合 / 聚会

    初见安~这里是传送门:洛谷P4281紧急集合/聚会 题目描述 欢乐岛上有个非常好玩的游戏,叫做"紧急集合".在岛上分散有N个等待点,有N-1条道路连接着它们,每一条道路都连接某两个 ...

  5. 题解【[AHOI2008]紧急集合 / 聚会】

    简化版题目: 有一棵 N N N个节点的树,和 Q Q Q组询问 有三个人分别在点 x , y , z x,y,z x,y,z现在希望你找到一个点,使得 三个人到这个点的距离和最小. 题目分析 首先, ...

  6. BZOJ 1787 AHOI2008 紧急集合 倍增LCA

    题目大意:给定一棵树,多次询问到三个点距离之和最小的点和距离 首先易知到两个点距离之和最小的点一定在两点间的路径上 于是到三个点距离之和最小的点一定在两两之间路径的交点上 然后很容易就会知道这个交点一 ...

  7. [Ahoi2008]Meet 紧急集合

    1787: [Ahoi2008]Meet 紧急集合 Time Limit: 20 Sec  Memory Limit: 162 MB http://www.lydsy.com/JudgeOnline/ ...

  8. 1787: [Ahoi2008]Meet 紧急集合

    1787: [Ahoi2008]Meet 紧急集合 Time Limit: 20 Sec  Memory Limit: 162 MB Submit: 1482  Solved: 652 [Submit ...

  9. bzoj1787 [Ahoi2008]Meet 紧急集合

    1787: [Ahoi2008]Meet 紧急集合 Time Limit: 20 Sec   Memory Limit: 162 MB Submit: 2272   Solved: 1029 [ Su ...

最新文章

  1. 编解码器架构中的桥(bridge)指什么
  2. 序列化和反序列化(转)
  3. 2月07日云栖精选夜读:观点 | 阿里云 MVP 唐俊飞:安全性可以认为是一种能力...
  4. 分分钟get「隔空传手」技能,网友:我想试试别的东西…
  5. 【转】Hibernate的Generator属性有7种class,本文简略描述了这7种class的意义和用法。...
  6. 胡正是什么lisp_《亲爱的挚爱的》演员公开,吴白还是胡一天,grunt却换了人
  7. dubbo官方文档_不可忽视的Dubbo线程池
  8. 如何将iPhone或iPad更新到iOS 11
  9. python创建虚拟串口
  10. java muki_再次学习 java 类的编译
  11. NSA 分享植入 web shell 的常用漏洞列表
  12. linux安装python_最基础:如何安装Python?
  13. 3-unit2 高级网络配置
  14. 关于编译ns3的myfirst.cc问题
  15. 微信小程序获取年月日周及早上、中午、晚上
  16. 手码万字-带你全面了解存储基础知识
  17. RMQ与SparseTable(ST表)
  18. 拉格朗日对偶函数拉格朗日对偶问题
  19. ultraiso制作u盘启动盘教程图文详解
  20. YII Framework学习教程-用YIIC快速创建YII应用之三-2011-11-11

热门文章

  1. python3 http.server 本地服务支持跨域
  2. Java_方法的调用①及案例
  3. 【数学建模】数模day13-灰色系统理论I-灰色关联与GM(1,1)预测
  4. 64位以内Rabin-Miller 强伪素数测试和Pollard rho 因数分解解析
  5. 爆破专业学生任母校爆破工作总指挥走红
  6. JAVA实现WC.exe功能
  7. 暑假做题记录【实时更新】
  8. bzoj1597[Usaco2008 Mar]土地购买
  9. 在Maven仓库中添加Oracle JDBC驱动
  10. 解决Maven报Plugin execution not covered by lifecycle configuration