洛谷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;
}