1. 程式人生 > >洛谷3320 SDOI2015尋寶遊戲(set+dfs序)(反向迭代器的注意事項!)

洛谷3320 SDOI2015尋寶遊戲(set+dfs序)(反向迭代器的注意事項!)

題目連結

S T L STL 坑害了一個晚上,真的菜的沒救了啊。

準確的說是一個叫 r e v

e r s e   i t e r a t
o r reverse\ iterator 的東西,就是我們經常用的 r b e g i
n ( ) rbegin()

有一個非常重要的性質

在反向迭代器中,++相當於正常的–,--相當於正常的++

也就是說
假設我們要訪問 s e t set 中的倒數第二個元素,我們要 + + s . r b e g i n ( ) ++s.rbegin()

而不是一些別的東西


我們回到這個題,對於這個題目來說,其實我的第一反應是虛樹,QWQ但事實證明,並不能用虛樹來解決這個問題。

我們可以通過一些方式,發現,無論從哪個有寶藏的點出發,訪問所有點的總距離都是一定的。那麼我們可以強制按照 d f n dfn 順序,每個點從 d f n dfn 的上一個節點走過來,然後走向 d f n dfn 的下一個節點,那麼刪除的之後,我們要是知道每個點的前驅和後繼的話,就可以考慮直接更新 a n s ans 了,(但是要特判第一個點和最後一個點,第一個點的前驅是最後一個點,最後一個點的後繼是第一個點)

那麼既然需要一個排序+前驅後繼的資料結構,自然就是 s e t set

不過需要注意的是。

r b e g i n ( ) 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;
}