洛谷3320 SDOI2015寻宝游戏(set+dfs序)(反向迭代器的注意事项!)
被\(STL\)坑害了一个晚上,真的菜的没救了啊。
准确的说是一个叫\(reverse\ iterator\)的东西,就是我们经常用的\(rbegin()\)
有一个非常重要的性质
在反向迭代器中,++相当于正常的--,--相当于正常的++
也就是说
假设我们要访问\(set\)中的倒数第二个元素,我们要\(++s.rbegin()\)
而不是一些别的东西
好
我们回到这个题,对于这个题目来说,其实我的第一反应是虚树,QWQ但事实证明,并不能用虚树来解决这个问题。
我们可以通过一些方式,发现,无论从哪个有宝藏的点出发,访问所有点的总距离都是一定的。那么我们可以强制按照\(dfn\)顺序,每个点从\(dfn\)的上一个节点走过来,然后走向\(dfn\)的下一个节点,那么删除的之后,我们要是知道每个点的前驱和后继的话,就可以考虑直接更新\(ans\)了,(但是要特判第一个点和最后一个点,第一个点的前驱是最后一个点,最后一个点的后继是第一个点)
那么既然需要一个排序+前驱后继的数据结构,自然就是\(set\)了
不过需要注意的是。
\(rbegin()\)的问题!!!!!!!!!!!!!!
直接给代码了
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define mk makr_pair
#define ll long long
#define int long long
using namespace std;
inline int read()
{
  int x=0,f=1;char ch=getchar();
  while (!isdigit(ch)) {if (ch=='-') f=-1;ch=getchar();}
  while (isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
  return x*f;
}
const int maxn = 2e5+1e2;
const int maxm = 2*maxn;
const int inf = 1e9;
int point[maxn],nxt[maxm],to[maxm];
int cnt,n,m;
int dfn[maxn],deep[maxn],f[maxn][21];
set<int> s;
int tot;
int dis[maxn];
int mp[maxn];
int ans;
int val[maxm],tag[maxn];
void addedge(int x,int y,int w)
{
 nxt[++cnt]=point[x];
 to[cnt]=y;
 val[cnt]=w;
 point[x]=cnt;
}
void dfs(int x,int fa,int dep)
{
   deep[x]=dep;
   dfn[x]=++tot;
   mp[tot]=x;
   for (int i=point[x];i;i=nxt[i])
   {
     int p = to[i];
     if (p==fa) continue;
    f[p][0]=x;
    dis[p]=dis[x]+val[i];
  dfs(p,x,dep+1);
   }
}
void init()
{
 for (int j=1;j<=20;j++)
   for (int i=1;i<=n;i++)
     f[i][j]=f[f[i][j-1]][j-1];
}
int go_up(int x,int d)
{
 for (int i=0;i<=20;i++)
   if ((1<<i) & d) x=f[x][i];
 return x;
}
int lca(int x,int y)
{
 if (deep[x]>deep[y]) x=go_up(x,deep[x]-deep[y]);
 else y=go_up(y,deep[y]-deep[x]);
 if (x==y) return x;
 for (int i=20;i>=0;i--)
 {
  if (f[x][i]!=f[y][i])
  {
   x=f[x][i];
   y=f[y][i];
  }
 }
 return f[x][0];
}
int getdis(int x,int y)
{
 return dis[x]-2*dis[lca(x,y)]+dis[y];
}
int getpre(int x)
{
 set<int> :: iterator it = s.lower_bound(x);
 --it;
 if ((*it)==-inf) return mp[*(++s.rbegin())];
 else return mp[(*it)];
}
int getlas(int x)
{
 set<int> :: iterator it = s.upper_bound(x);
 if ((*it)==inf) return mp[*(++s.begin())];
 else return mp[(*it)];
}
signed main()
{
  //freopen("game.in.txt","r",stdin);
  //freopen("game.out","w",stdout);
  n=read();m=read();
  for (int i=1;i<n;i++)
  {
    int x=read(),y=read(),w=read();
    addedge(x,y,w);
    addedge(y,x,w);
  }
  dfs(1,0,1);
  init();
  s.insert(inf);
  s.insert(-inf);
  for (int i=1;i<=m;i++)
  {
    int x=read();
    if (tag[x])
    {
     int pre = getpre(dfn[x]);
     int last = getlas(dfn[x]);
    // cout<<"you:"<<pre<<" "<<last<<endl;
     ans=ans-getdis(pre,x)-getdis(last,x);
     ans=ans+getdis(pre,last);
     s.erase(dfn[x]);
     tag[x]=0;
  }
  else
  {
   if (s.size()==2)
  {
    s.insert(dfn[x]);
    tag[x]=1;
    cout<<ans<<"\n";
    continue;
     }
   int pre = getpre(dfn[x]);
   //cout<<1<<endl;
     int last = getlas(dfn[x]);
    // cout<<"meiyou:"<<pre<<" "<<last<<" "<<getdis(pre,x)<<" "<<lca(pre,x)<<" "<<dis[pre]<<" "<<dis[x]<<endl;
     ans=ans-getdis(pre,last);
  ans=ans+getdis(pre,x)+getdis(last,x);
     s.insert(dfn[x]);
     tag[x]=1;
  }
  cout<<ans<<"\n";
  }
  return 0;
}
洛谷3320 SDOI2015寻宝游戏(set+dfs序)(反向迭代器的注意事项!)的更多相关文章
- [洛谷P3320] SDOI2015 寻宝游戏
		问题描述 小B最近正在玩一个寻宝游戏,这个游戏的地图中有N个村庄和N-1条道路,并且任何两个村庄之间有且仅有一条路径可达.游戏开始时,玩家可以任意选择一个村庄,瞬间转移到这个村庄,然后可以任意在地图的 ... 
- [bzoj3991] [洛谷P3320] [SDOI2015] 寻宝游戏
		Description 小B最近正在玩一个寻宝游戏,这个游戏的地图中有 \(N\) 个村庄和 \(N-1\) 条道路,并且任何两个村庄之间有且仅有一条路径可达.游戏开始时,玩家可以任意选择一个村庄,瞬 ... 
- 洛谷 P3320 [SDOI2015]寻宝游戏
		因为寻宝路径是一个环,所以寻宝花费的最小时间与起点无关.宝应当按照所有宝藏所在位置的 dfs 序进行才能够使得花费的时间最短.设 \(dist_i\) 表示 \(i\) 到树根的最短距离,那么树上任意 ... 
- BZOJ3991 [SDOI2015]寻宝游戏  【dfs序 + lca + STL】
		题目 小B最近正在玩一个寻宝游戏,这个游戏的地图中有N个村庄和N-1条道路,并且任何两个村庄之间有且仅有一条路径可达.游戏开始时,玩家可以任意选择一个村庄,瞬间转移到这个村庄,然后可以任意在地图的道路 ... 
- Luogu 3320 [SDOI2015]寻宝游戏
		一开始还真没想到. 发现从所有有宝藏的点出发绕一圈只要不刻意绕路答案都是一样的,即我们呢要求的最后答案$ans = dis(x_1, x_2) + dis(x_2, x_3) +... + dis(x ... 
- 洛谷P3178 [HAOI2015]树上操作(dfs序+线段树)
		P3178 [HAOI2015]树上操作 题目链接:https://www.luogu.org/problemnew/show/P3178 题目描述 有一棵点数为 N 的树,以点 1 为根,且树点有边 ... 
- [Bzoj3991]寻宝游戏(dfs序+set)
		Description 题目链接 Solution 用set按dfs序维护当前的宝物序列,那么答案为相邻2个点的距离加上头尾2个的距离 Code #include <cstdio> #in ... 
- 洛谷 p1123 取数游戏【dfs】
		题目链接:https://www.luogu.org/problemnew/show/P1123 转载于:>>>>>> 题目描述 一个N×M的由非负整数构成的数字矩 ... 
- 【LG3320】[SDOI2015]寻宝游戏
		[LG3320][SDOI2015]寻宝游戏 题面 洛谷 题解 不需要建虚树的虚树2333... 贪心地想一下,起始节点肯定是在关键点上,访问顺序就是\(dfs\)序. 那么对于每次询问, \[ An ... 
随机推荐
- 一次PHP大马提权
			记一次PHP提权 发现 PHP大马:指木马病毒:PHP大马,就是PHP写的提取站点权限的程序:因为带有提权或者修改站点功能,所以称为叫木马. 自从师哥那里听说过之后,一直感叹于PHP大马的神奇...但 ... 
- 搭建私服仓库:(一)Windows安装Nuxus
			Nexus下载 官网.官网下载.百度云盘 提取码:su33 将nexus下载下来,以2.14.5的windows版本为例子(3.x暂时下载不下来,迅雷会员都不行) 下载后进行解压,得到以下目录: 其中 ... 
- 二、grep文本搜索工具
			grep命令作为Unix中用于文本搜索的神奇工具,能够接受正则表达式,生成各种格式的输出.除此外,它还有大量有趣的选项. # 搜索包含特定模式的文本行: [root@centos8 ~]#grep p ... 
- www迁移
			www迁移主要就是2部分: 1)官网页面架构,即 ./drupal/index.php 2)官网图片,即 ./drupal/assets/ 目录下的文件 1. 在ubuntu上搭建基础v1.0环境 2 ... 
- Jsoup快速查询
			一.selector选择器 二.Xpath查询 
- git换行符自动转换导致整个文件被修改的解决方案
			不少开发者可能遇到过这个问题:从git上拉取服务端代码,然后只修改了一处地方,准备提交时,用diff软件查看,却发现整个文件都被修改了.这是git自动转换换行符导致的问题. 原因 不同操作系统使用的换 ... 
- php在类中使用回调函数 如array_map
			<?php class foo { var $var; function bar() { array_map(array($this, "baz"), ar ... 
- Docker系列(26)- 发布镜像到阿里云容器服务
			1.登录阿里云 2.找到容器镜像服务 3.创建命名空间 4.创建镜像仓库 5.上传镜像 
- Linux系列(27) - 三剑客grep、awk、sed
			Linux下一切皆文件,对Linux的操作就是对文件的处理 Linux中最重要的三个命令在业界被称为"三剑客",它们是awk,sed,grep 正则表达式就好比一个模版,这个模板就 ... 
- Shell系列(23)- 字符截取命令sed
			简述 字符替换命令sed 和vi功能相似,但是vi是给用户用的,sed是给脚本用的 sed是一种几乎包括在所有的UNIX平台(包括Linux)的轻量级流编辑器.s sed主要是用来将数据进行选取.替换 ... 
