SDOI2015寻宝游戏 dfs序+set

SDOI2015寻宝游戏

好像是一道虚树入门题?

虚树???不会不会我弱死了。。

Solution:

关键点间的最小路径,就是在保证尽量少走重复路的前提下走出来的一条经过所有关键点的路径。

基于这个思想,我们思考怎样走出来的会是重复最少的呢???

不妨想一想dfs,我们dfs时就是保证了每个点只遍历一次,每条边只遍历了两次,这已经是最优的情况了!!

所以,对于这些关键点,把它们按照dfs序遍历,可以发现路径就是最小的。

对于修改,我们相当于只要维护了关键点dfs序,就只要对应的在序列上插入、删除就好了,用set即可。

说实话,本人运用set等STL的能力极差,所以每每遇到这种需要set等的题,就会。。。enenen

Code↓:

#include<set>
#include<cmath>
#include<string>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define RG register
#define IL inline
#define LL long long
#define DB double 
using namespace std;

IL int gi() {
    char ch=getchar(); RG int x=0,q=0;
    while(ch<'0'||ch>'9') q=ch=='-'?1:q,ch=getchar();
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return q?-x:x;
}

const int N=1e5+10;

set<int> seq;
set<int>::iterator IT,pr,sf;

LL ans,dis[N];
int n,m,Time,tot,head[N],mp[N],dep[N],dfn[N],dot[N],f[N][21];

struct EDGE{int next,to,ver;}e[N<<1];
IL void make(int a,int b,int c) {
    e[++tot]=(EDGE){head[a],b,c},head[a]=tot;
    e[++tot]=(EDGE){head[b],a,c},head[b]=tot;
}

void dfs(int x,int fx) {
    RG int i,y;
    dfn[x]=++Time,mp[Time]=x;
    for (i=head[x],dep[x]=dep[fx]+1;i;i=e[i].next)
        if ((y=e[i].to)!=fx) f[y][0]=x,dis[y]=dis[x]+e[i].ver,dfs(y,x); 
}

IL void getf() {
    RG int i,j;
    for (i=1;i<=18;++i)
        for (j=1;j<=n;++j)
            f[j][i]=f[f[j][i-1]][i-1];
}

IL void Find(int x) {
    IT=seq.lower_bound(dfn[x]);
    if (IT==seq.begin()) pr=seq.end(),pr--;
    else pr=IT,pr--;
    sf=IT,sf++;
    if (sf==seq.end()) sf=seq.begin();
}

IL int Lca(int x,int y) {
    RG int i;
    if (dep[x]<dep[y]) swap(x,y);
 	for (i=18;i>=0;--i)
        if (dep[f[x][i]]>=dep[y]) x=f[x][i];
    if (x==y) return x;
    for (i=18;i>=0;--i)
        if (f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
    return f[x][0];
}

IL LL Path(int x,int y) {return dis[x]+dis[y]-2*dis[Lca(x,y)];}

int main ()
{
    RG int i,x,y,z,pre=0,suf=0;
    n=gi(),m=gi();
    for (i=1;i<n;++i) x=gi(),y=gi(),z=gi(),make(x,y,z);
    for (i=1,dfs(1,0),getf();i<=m;++i) {
        dot[x=gi()]^=1;
        if (dot[x]) {
            seq.insert(dfn[x]),Find(x);
            suf=mp[*sf],pre=mp[*pr];
            ans+=Path(pre,x)+Path(x,suf)-Path(pre,suf);
        }
        else {
            Find(x),seq.erase(dfn[x]);
            suf=mp[*sf],pre=mp[*pr];
            ans+=Path(pre,suf)-Path(pre,x)-Path(x,suf);
        }
        printf("%lld\n",ans);
    }
    return 0;
}

The End

posted @ 2019-03-28 19:00  薄荷凉了夏  阅读(144)  评论(0编辑  收藏  举报