题目大意:

给一棵带权树,和一个集合S,初始为空。现有两种操作:

1、选择某个顶点加入S

2、将S中某个顶点去掉。

问:每次操作后,使得集合S中的点联通的最小边权和是多少。

一、思考问题的本质是什么?

要使边权和最小,也即每次增加的边权要求最小。

当添加第一个顶点的时候,增加的边权为0

添加第二个顶点的时候,增加的边权为该点到第一个顶点的路径长度。

添加第三个顶点的时候,增加的最小边权应当是该点到第一个顶点和第二个顶点形成的链的距离。(当然,若在链上,距离为0)

……

就是说,添加顶点u的时候,之前添加的顶点已经形成了若干条链(任意两个顶点构成一条)

此时要找的就是u到这些链的最短的距离是多少,也就是:在之前添加的顶点中(集合S中)找两个顶点x,y,使得u到x、y构成的链的距离最短。

二、如何来找这两个点?

观察一棵树中顶点的DFS序,发现有如下特点:

1、对于任意一个结点u,DFS序比它大的结点,由u的子孙和u的右侧的所有节点(不含根节点)构成。

2、对于任意一个结点u,DFS序比它小的结点,由u到根节点经过的所有结点(不含u本身,其实就是u的所有祖先啦)和u的左侧的所有节点构成。

这也就意味着,可以通过DFS序,来确定树中两点的相对位置。

对于添加的点u:

1、若集合S中所有点的DFS序都比它小,那么集合中所有点都位于u的左侧或者是u的某个祖先结点。若存在某个点是u的祖先,为了使得增加的距离最少,那么找距离u最近的那个,即DFS序最大的那个,设为x,再任意选一个顶点y,求u到x-y链的距离即可;若均位于u的左侧,此时又有两种情况,一种是所有顶点都在一棵子树中,此时找DFS序最小的那个点(因为最靠近u)作为x,再任选一个作为y,再一种是顶点分散在u的左侧的不同子树中,那么选取DFS序最小的和最大的作为x、y(最小的和最大的必然位于不同子树中),求u到链x-y的距离即可。综上,为了统一方便,分别找集合S中DFS序最小和最大的两个点作为x、y即可。

2、若集合S中所有点的DFS序都比它大,那么集合中所有点都位于u的右侧或者是u的子孙,同上分情况考虑,可以得到:也是找集合S中DFS序最小和最大的两个点作为x、y。

3、若集合S中的点的DFS序有比u大的,也有比u小的,此时分如下几种情况:

(1)比顶点u的DFS序大的点都在u的右侧,比顶点u的DFS序小的点都在u的左侧。此时任意选取左侧一个点和右侧一个点作为x、y即可。

(2)存在u的子孙在集合S中,且比顶点u的DFS序小的点都在u的左侧。容易知道,此时无需再增加边。即选取的时候只需保证链x-y经过u即可。

(3)比顶点u的DFS序大的点都在u的右侧,且存在u的祖先结点在S中。此时选取u的祖先结点DFS序最大的那个(也就是DFS序比u小的最大的那个),然后在右侧随便选一个即可。

(4)存在u的子孙在集合S中,且存在u的祖先结点在S中,显然此时也无需再增加边,选取的时候保证链x-y经过u即可。

综上,为了统一方便,分别找集合S中DFS序比u小的最大的那个、比u大的任意一个即可。

三、找到了之后如何求点到链的距离?

设dis[u]表示顶点u到根节点的距离

那么u点 到x点 距离表示为 dis[u]+dis[x]-2dis[lca(x,u)]
那么u点 到y点 距离表示为 dis[u]+dis[y]-2dis[lca(y,u)]
上面的距离的和减掉 x到y的距离dis[x]+dis[y]-2dis[lca(y,x)]

减去之后,发现得到的结果刚好是u到链x-y距离的2倍,除以2就是所求的结果了。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<stack>
#include<cmath>
#include<set>
#include<queue>
#include<vector>
using namespace std;
#define maxn 100001
#define maxq 70001
struct Edge{int to,next,w;
}edge[maxn<<1];int dis[maxn],head[maxn],stk[maxn<<1],dep[maxn<<1],cnt,pos[maxn],E[maxn<<1],DFN[maxn],dfn,f[maxn<<1][20],dfn2,D[maxn];
bool vis[maxn];inline void add(int u,int v,int w)
{edge[cnt].to=v;edge[cnt].w=w;edge[cnt].next=head[u];head[u]=cnt++;
}void init()
{memset(head,-1,sizeof(head));memset(pos,-1,sizeof(pos));memset(vis,0,sizeof(vis));cnt=dfn=dfn2=0;
}void dfs(int u,int deep)
{if(pos[u]!=-1) return;DFN[dfn2]=u,D[u]=dfn2++,E[dfn]=u,dep[dfn]=deep,pos[u]=dfn++;for(int i=head[u];~i;i=edge[i].next){int v=edge[i].to;if(pos[v]==-1){dis[v]=dis[u]+edge[i].w;dfs(v,deep+1);E[dfn]=u,dep[dfn++]=deep;}}
}void init_RMQ(int n)
{for(int i=1;i<=n;++i) f[i][0]=i;for(int j=1;(1<<j)<=n;++j)for(int i=1;i+(1<<j)-1<=n;++i){if(dep[f[i][j-1]]<dep[f[i+(1<<(j-1))][j-1]]) f[i][j]=f[i][j-1];else f[i][j]=f[i+(1<<(j-1))][j-1];}
}inline int RMQ(int L,int R)
{int k=0;while(1<<(k+1)<=R-L+1) ++k;if(dep[f[L][k]]<dep[f[R-(1<<k)+1][k]]) return f[L][k];return f[R-(1<<k)+1][k];
}inline int lca(int u,int v)
{if(pos[u]>pos[v]) return E[RMQ(pos[v],pos[u])];return E[RMQ(pos[u],pos[v])];
}set<int> S;
set<int>::iterator it;int cal(int u)
{int x,y;if(S.size()<1) return 0;it=S.lower_bound(D[u]);if(it==S.begin()||it==S.end()){x=DFN[*S.begin()];y=DFN[*S.rbegin()];}else{x=DFN[*it];--it;y=DFN[*it];}return dis[u]+dis[lca(x,y)]-dis[lca(x,u)]-dis[lca(y,u)];}int main()
{int T,n,i,u,v,w,q,k;scanf("%d",&T);for(int ca=1;ca<=T;++ca){scanf("%d%d",&n,&q);init();S.clear();for(i=1;i<n;++i){scanf("%d%d%d",&u,&v,&w);add(u,v,w);add(v,u,w);}dis[1]=0;dfs(1,0);init_RMQ(2*n-1);printf("Case #%d:\n",ca);int ans=0;while(q--){scanf("%d%d",&k,&u);if(k==1){if(!vis[u]){vis[u]=1;ans+=cal(u);S.insert(D[u]);}}else{if(vis[u]){vis[u]=0;S.erase(D[u]);ans-=cal(u);}}printf("%d\n",ans);}}return 0;
}

hdu 5296 Annoying problem (LCA)相关推荐

  1. hdu A + B Problem II(大数相加,数组实现)

    hdu A + B Problem II(大数相加,数组实现) 题目走起 注意最后一个case 不需要换行 下面代码 #include<stdio.h> #include<strin ...

  2. HDU.1001 Sum Problem

    原题 HDU.1001 Sum Problem 分类 杂题 题意 计算从1到正整数n的累加和. 输入/输出 要求与格式 输入内容 每行输入一个正整数 输出结果 结果为累加和 输出格式 每个输出结果独占 ...

  3. [HDU 5445]Food Problem[多重背包]

    题目链接:[HDU 5445]Food Problem[多重背包] 题意分析: 有n种类型的点心,每种提供t的能量,占据u的空间,有v个: 有m种类型的卡车,每种容量x,雇佣花费y,能提供z辆: 点心 ...

  4. hdu 5266(线段树+LCA)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5266 解题思路: 考虑dfs序,通过在简单的证明可知L~R的LCA为L ~R 中dfs序较小的那个位置 ...

  5. hdu 3549 Flow Problem(最大流模板题)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3549 Problem Description Network flow is a well-known ...

  6. hdu 1023 Train Problem II

    题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=1212 Train Problem II Description As we all know the ...

  7. HDU 5427 A problem of sorting 水题

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5427 A problem of sorting Time Limit: 2000/1000 MS ( ...

  8. HDU - 3078 Network 倍增LCA

    倍增lca,把路径上点全部拉出来拍个序输出第k大就过了. 不知道怎么过的,咱也不敢问. #include<stdio.h> #include<string.h> #includ ...

  9. HDU 1022[Train Problem I] 栈的应用

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1022 题目大意:一列序列为s1的车厢是否能通过车站的中转以序列s2出站.白皮上有. 关键思想:栈的应用 ...

  10. HDU 3549 Flow Problem (dinic模版 isap模版)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3549 题意: 给你一个有向图,问你1到n的最大流. dinic模版 (n*n*m) 1 #includ ...

最新文章

  1. Python可视化matplotlib绘制三维可视化图形(Three-Dimensional)
  2. 网络推广外包浅析当下网站优化处于健康状态有利于网络推广外包
  3. 解决安装ROS 时rosdep update 问题(time out)
  4. (转)SQL Case when 的使用方法
  5. Linux格式化sd卡博客,linux设备驱动那点事儿之SD卡驱动理论篇
  6. Fibonacci思想的灵活应用(洛谷P1011题题解,Java语言描述)
  7. StratoVirt在x86_64下的初体验
  8. 不玩游戏,855和730处理器在日常应用的速度差别有多大?
  9. android 腾讯 gt,源码解读腾讯 GT 的性能测试方案
  10. redis分布式锁简单总结
  11. matlab 阶乘函数
  12. 2022年天猫618超级红包玩法入口
  13. 软件测试kpi绩效考核表,测试工程师绩效考核表.xls
  14. 以替换为主的疯狂填词、sub()介绍
  15. 魔兽对战平台服务器更新维护什么,官方对战平台每天5点维护是个什么梗
  16. 《东周列国志》第七十九回 归女乐黎弥阻孔子 栖会稽文种通宰嚭
  17. 一个步骤结束机房电脑红蜘蛛的控制
  18. python interpreter配置_PyCharm使用之配置SSH Interpreter
  19. Android简单电子书
  20. C#利用Microsoft.Office.Interop.Excel导出excel文件

热门文章

  1. 信息安全实验:实现一个fake-wifi
  2. jquery fullpage
  3. 【ROS2学习】二、用python编写publisher和subscriber
  4. Java是如何实现外卖订餐系统的
  5. 班级学生德育量化管理系统_德育积分学分考核系统_学生操行日常行为规范考核系统
  6. 使用工具Android Studio实现一个简单的Android版的新闻APP
  7. android第三方浏览器存在泄露用户隐私漏洞
  8. 中职学校计算机教学参考文献,中职计算机教学论文
  9. 应届毕业生求职,注意事项
  10. 网络安全之密码安全基础