题目详见蓝皮书【算法竞赛:进阶指南】。


题目大意:

就是给你一颗树,然后我们要在上面进行三种操作:

 1.标记某个点  或者  2.撤销某个点的标记  以及   3.询问标记点在树上连通所需的最短总边权


数据范围:

点数以及操作数:1e5,边权:1e9(意思就是答案要 long long 存)。


分析:

这道题比赛的时候看的是真懵逼。。。

表示只会 n^3 做法(最多会n^2),以及特殊形态(比如链或者菊花图)的骗分法。

然鹅正解大概是 $O(n log n)$  的做法,和树搭上了关系,加上这数据范围...

于是正解真是这个复杂度。(看到标程的时候表示惊讶,我太弱了)

标算就是用的dfs序加上lca的算法(如题)

首先我们不考虑 2、3 操作,我们先考虑如果树上有 k 个点被标记了,我们要得到树上 k 个点连通图的最小总边权。

我们可以在纸上画出这棵树以及标记的点,然后我们从左到右把点连成一块。

这时我们发现每两个相邻的点之间(相当于dfs序)的距离加上最后一个点和第一个点的距离,和正好是答案的两倍。

也就是说,如果把这些标记点按照dfs序排成一列,首尾相连形成一个环的话,答案就是这个环相邻点距离之和除以二。

(这种东西考场上怎么做得出来嘛)

那么我们回到原题,如果用上面的方法暴力处理答案,那么复杂度是 $O(n^{2} log n)$ 的(还不如 我自己想到的 n^2 咧)。

那么我们结合加点删点特殊的性质,以此优化算法复杂度。

我们发现加点其实就是在原环两相邻点之间插入了一个新点,然后原来两个相邻点的贡献没了,但是多了新点与这两个点分别的贡献。

那么删点类似的,就是令原环中某个点与相邻的两个点之间的贡献删除,并且多了这两个点之间的距离的贡献。

于是我们就可以用一个set来维护标记点,然后每次求距离的时候要用到 lca。

(lca建议常数小的树剖,倍增效率感人,tarjan 的话比较冷门基本不考虑)

那么我们就可以愉快地抄敲代码了!


代码 :

  1. //by Judge
  2. #include<bits/stdc++.h>
  3. #pragma GCC optimize(2)
  4. #define It set<int>::iterator
  5. #define ll long long
  6. using namespace std;
  7. const int M=1e5+;
  8. #define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
  9. char buf[<<],*p1,*p2;
  10. inline int read(){ int x=;
  11. char c=getchar(); while(!isdigit(c)) c=getchar();
  12. for(;isdigit(c);c=getchar()) x=x*+c-''; return x;
  13. } inline int cread(){ char c=getchar();
  14. while(c!='+'&&c!='-'&&c!='?') c=getchar();
  15. return c=='?'?:(c=='+'?:);
  16. } char sr[<<],z[];int C=-,Z;
  17. inline void Ot(){fwrite(sr,,C+,stdout),C=-;}
  18. inline void print(ll x,char chr='\n'){
  19. if(C><<)Ot(); while(z[++Z]=x%+,x/=);
  20. while(sr[++C]=z[Z],--Z);sr[++C]=chr;
  21. } int n,m,pat,tim,head[M],f[M],son[M]; ll ans,dis[M];
  22. int siz[M],top[M],dep[M],dfn[M],p[M]; set<int> s;
  23. struct Edge{ int to,val,nxt;
  24. Edge(int v,int c,int x):to(v),val(c),nxt(x){} Edge(){}
  25. }e[M<<];
  26. inline void add(int u,int v,int c){
  27. e[++pat]=Edge(v,c,head[u]),head[u]=pat;
  28. e[++pat]=Edge(u,c,head[v]),head[v]=pat;
  29. }
  30. #define v e[i].to
  31. void dfs(int u,int fa){
  32. siz[u]=,f[u]=fa,dep[u]=dep[fa]+;
  33. for(int i=head[u];i;i=e[i].nxt) if(v^fa){
  34. dis[v]=dis[u]+e[i].val,
  35. dfs(v,u),siz[u]+=siz[v];
  36. if(siz[v]>siz[son[u]]) son[u]=v;
  37. }
  38. } void dfs(int u){
  39. dfn[u]=++tim,p[tim]=u;
  40. if(!top[u]) top[u]=u; if(!son[u]) return ;
  41. top[son[u]]=top[u],dfs(son[u]);
  42. for(int i=head[u];i;i=e[i].nxt)
  43. if(v^f[u]&&v^son[u]) dfs(v);
  44. }
  45. #undef v
  46. inline int lca(int u,int v){
  47. while(top[u]^top[v])
  48. (dep[top[u]]>dep[top[v]])?
  49. u=f[top[u]]:v=f[top[v]];
  50. return dep[u]<dep[v]?u:v;
  51. } inline ll get(int u,int v){
  52. return dis[u]+dis[v]-dis[lca(u,v)]*;
  53. } inline It L(It it){
  54. return (it==s.begin())?--s.end():--it;
  55. } inline It R(It it){
  56. return (it==--s.end())?s.begin():++it;
  57. }
  58. int main(){
  59. n=read();
  60. for(int i=,u,v,c;i<n;++i)
  61. u=read(),v=read(),
  62. c=read(),add(u,v,c);
  63. dfs(,),dfs(),m=read();
  64. for(int opt,x,t;m;--m){
  65. opt=cread(); It it;
  66. if(opt==) print(ans/);
  67. else if(opt==){ x=read();
  68. if(s.size()){
  69. it=s.lower_bound(dfn[x]);
  70. if(it==s.end()) it=s.begin(); t=*L(it);
  71. ans+=get(x,p[t])+get(x,p[*it])-get(p[t],p[*it]);
  72. } s.insert(dfn[x]);
  73. } else if(opt==){ x=read();
  74. if(s.size()>){
  75. it=s.find(dfn[x]),t=*L(it),it=R(it);
  76. ans-=get(x,p[t])+get(x,p[*it])-get(p[t],p[*it]);
  77. } s.erase(dfn[x]);
  78. }
  79. } return Ot(),;
  80. }

蓝皮书:异象石 【dfs序+lca】的更多相关文章

  1. bzoj2819 DFS序 + LCA + 线段树

    https://www.lydsy.com/JudgeOnline/problem.php?id=2819 题意:树上单点修改及区间异或和查询. 思维难度不高,但是题比较硬核. 整体思路是维护每一个结 ...

  2. BZOJ 3083: 遥远的国度 [树链剖分 DFS序 LCA]

    3083: 遥远的国度 Time Limit: 10 Sec  Memory Limit: 1280 MBSubmit: 3127  Solved: 795[Submit][Status][Discu ...

  3. HDU 3966 dfs序+LCA+树状数组

    题目意思很明白: 给你一棵有n个节点的树,对树有下列操作: I c1 c2 k 意思是把从c1节点到c2节点路径上的点权值加上k D c1 c2 k 意思是把从c1节点到c2节点路径上的点权值减去k ...

  4. HDU 6203 ping ping ping(dfs序+LCA+树状数组)

    http://acm.hdu.edu.cn/showproblem.php?pid=6203 题意: n+1 个点 n 条边的树(点标号 0 ~ n),有若干个点无法通行,导致 p 组 U V 无法连 ...

  5. HDU 5296 Annoying problem dfs序 lca

    Annoying problem 题目连接: http://acm.hdu.edu.cn/showproblem.php?pid=5296 Description Coco has a tree, w ...

  6. Gym 101142G : Gangsters in Central City(DFS序+LCA+set)

    题意:现在有一棵树,1号节点是水源,叶子节点是村庄,现在有些怪兽会占领一些村庄(即只占领叶子节点),现在要割去一些边,使得怪兽到不了水源.给出怪兽占领和离开的情况,现在要割每次回答最小的割,使得怪兽不 ...

  7. POJ 2763 Housewife Wind(DFS序+LCA+树状数组)

    Housewife Wind Time Limit: 4000MS   Memory Limit: 65536K Total Submissions: 11419   Accepted: 3140 D ...

  8. BZOJ3991 [SDOI2015]寻宝游戏 【dfs序 + lca + STL】

    题目 小B最近正在玩一个寻宝游戏,这个游戏的地图中有N个村庄和N-1条道路,并且任何两个村庄之间有且仅有一条路径可达.游戏开始时,玩家可以任意选择一个村庄,瞬间转移到这个村庄,然后可以任意在地图的道路 ...

  9. BZOJ 4999: This Problem Is Too Simple! DFS序+LCA+树状数组+离线

    Code: #include<bits/stdc++.h> #define setIO(s) freopen(s".in","r",stdin) , ...

随机推荐

  1. zk创建集群

    在单机环境下和创建集群. 需要注意的点: 配置数据文件myid 1/2/3 对应server.1/2/3 通过./zkCli.sh -server [ip]:[port]  检测集群是否创建成功 在z ...

  2. C#设计模式(9)——代理模式

    1.代理模式介绍 在软件开发中有时会遇到不能直接使用对象的问题,如我们要使用的对象在进程外,甚至在远程的机器上,但是我们要使用这个对象的功能怎么办呢?代理模式就可以用来解决这个问题.举一个生活中的例子 ...

  3. 微服务之consul

    一.概述 consul是google开源的一个使用go语言开发的服务发现.配置管理中心服务.内置了服务注册与发现框 架.分布一致性协议实现.健康检查.Key/Value存储.多数据中心方案,不再需要依 ...

  4. Linux下Maven私服Nexus3.x环境构建操作记录【转】

    Maven介绍Apache Maven是一个创新的软件项目管理和综合工具.Maven提供了一个基于项目对象模型(POM)文件的新概念来管理项目的构建,可以从一个中心资料片管理项目构建,报告和文件.Ma ...

  5. linux 精简开机自启动

    centos7 精简开机自启动 ntsysv rsyslog  crond  sshd network

  6. 【1】【leetcode-115】 不同的子序列 distinct-subsequences

    不同的子序列 distinct-subsequences(hard) (忘了,典型) 给定一个字符串 S 和一个字符串 T,计算在 S 的子序列中 T 出现的个数. 一个字符串的一个子序列是指,通过删 ...

  7. 一.ArrayList原理及实现学习总结

    一.ArrayList介绍 ArrayList是一种线性数据结构,它的底层是用数组实现的,相当于动态数组.与Java中的数组相比,它的容量能动态增长.类似于C语言中的动态申请内存,动态增长内存. 当创 ...

  8. Java动态代理 深度详解

    代理模式是设计模式中非常重要的一种类型,而设计模式又是编程中非常重要的知识点,特别是在业务系统的重构中,更是有举足轻重的地位.代理模式从类型上来说,可以分为静态代理和动态代理两种类型. 今天我将用非常 ...

  9. C# web IIS服务器 DateTime 带中文解决

    C# Web应用在某些电脑IIS上部署运行,读取当前时间带有中文,比如2018-5-1 星期一 上午 12:00:00,虽然使用Format转换可以解决,但代码量较大难免遗漏,会引发问题,为了解决该问 ...

  10. 通过修改配置文件修改MySQL的时区设置

    一.找到my.ini文件 二.将时区改为东八区 添加:default-time-zone='+08:00'