点分治好题

统计距离正常点分治统计即可,我们只需考虑何时达到最优

有两种情况:

第一:代价最大的询问两个端点在不同的两个子树中

因为这种情况下,无论根向那个子树移动都会等价地增加到达另一个端点的代价,因此此时总代价已经达到最小

第二:代价最大的询问有多组,且这些点不在同一棵子树中

同情况一,如果我们把根偏向其中某一棵子树移动的话,那么一定会等价地增大另一端的代价,因此总代价已经达到最小

这样的话直接统计就好了

贴代码:

#include <cstdio>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
using namespace std;
struct Edge
{
int nxt;
int to;
int val;
}edge[200005];
int q[100005][2];
int siz[100005];
int rt,s;
int head[100005];
int maxp[100005];
int ans=0x3f3f3f3f;
bool vis[100005];
int dis[100005];
int bel[100005];
int ccl[100005];
int col=0,typ=0;
int cnt=1,maxx=0;
int n,m;
void add(int l,int r,int w)
{
edge[cnt].nxt=head[l];
edge[cnt].to=r;
edge[cnt].val=w;
head[l]=cnt++;
}
void get_rt(int x,int fx)
{
siz[x]=1,maxp[x]=0;
for(int i=head[x];i;i=edge[i].nxt)
{
int to=edge[i].to;
if(to==fx||vis[to])continue;
get_rt(to,x);
siz[x]+=siz[to];
maxp[x]=max(maxp[x],siz[to]);
}
maxp[x]=max(maxp[x],s-siz[x]);
if(maxp[x]<maxp[rt])rt=x;
}
void dfs(int x,int fx,int dep)
{
dis[x]=dep;
if(!fx)bel[x]=0;
for(int i=head[x];i;i=edge[i].nxt)
{
int to=edge[i].to;
if(to==fx)continue;
if(!fx)col++;
bel[to]=col;
dfs(to,x,dep+edge[i].val);
}
}
int calc(int x)
{
dis[x]=maxx=0,dfs(x,0,0);
typ++;
for(int i=1;i<=m;i++)
{
ccl[i]=0;
if(dis[q[i][0]]+dis[q[i][1]]>maxx)maxx=dis[q[i][0]]+dis[q[i][1]],ccl[i]=++typ;
else if(dis[q[i][0]]+dis[q[i][1]]==maxx)ccl[i]=typ;
}
return typ;
}
void solve(int x)
{
vis[x]=1;
int k=calc(x);
int ori=0;
for(int i=1;i<=m;i++)
{
if((bel[q[i][0]]!=bel[q[i][1]])&&ccl[i]==k){ori=-1;break;}
else if(ccl[i]==k&&!ori)ori=bel[q[i][0]];
else if(ccl[i]==k)if(bel[q[i][0]]!=ori){ori=-1;break;}
}
ans=min(ans,maxx);
for(int i=head[x];i;i=edge[i].nxt)
{
int to=edge[i].to;
if(vis[to])continue;
if(bel[to]==ori)rt=0,s=siz[to],get_rt(to,x),solve(rt);
}
}
inline int read()
{
int f=1,x=0;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int main()
{
n=read(),m=read();
for(int i=1;i<n;i++)
{
int x=read(),y=read(),z=read();
add(x,y,z),add(y,x,z);
}
maxp[0]=0x3f3f3f3f;
for(int i=1;i<=m;i++)q[i][0]=read(),q[i][1]=read();
rt=0,s=n,get_rt(1,0),solve(rt);
printf("%d\n",ans);
return 0;
}

最新文章

  1. Bootstrap个人总结
  2. ural 1286. Starship Travel
  3. C++ struct与class
  4. Java 多线程 简单实例 (Runnable)
  5. VirtualBox Headless启动虚拟机
  6. HDOJ1005 数列
  7. Qt Painter放大时,event处理应该注意的要点
  8. Matlab基本数据类型
  9. yum笔记
  10. NET Core开发-读取配置文件Configuration
  11. 命令 修改WAMP中mysql默认空密码
  12. python+selenium自动化软件测试(第3章):unittest
  13. Java并发框架——AQS阻塞队列管理(二)——自旋锁优化
  14. JavaScript中Object.keys用法
  15. D2欧拉路,拓扑排序,和差分约束
  16. iOS开发 -------- storyBoard实现控制器添加childViewController
  17. 线程同步辅助类CyclicBarrier
  18. POJ2975:Nim(Nim博弈)
  19. 工具类: 用于模拟HTTP请求中GET/POST方式
  20. ReadyAPI创建功能测试的方法

热门文章

  1. java时间日期API
  2. IaaS--云上虚拟网络(何恺铎《深入浅出云计算》笔记整理)
  3. linux环境&quot;ModuleNotFoundError: No module named &#39;Cryptodome&#39;&quot;
  4. ASPNETCORE托管/部署到WindowService的问题[服务显示正在启动]
  5. C# Winform 多线程更新界面UI控件,解决界面卡顿问题(转)
  6. unity Android路径的相关部分代码
  7. wait notify 实例,生产消费者模式(转)
  8. win11 改键盘映射
  9. Xamarin.Android 踩坑记
  10. mvc和ef如何连接