【BZOJ3991】寻宝游戏(SDOI2015)-贪心+DFS序+set

测试地址:寻宝游戏
做法:本题需要用到DFS+set。
首先需要看出,无论从哪个点出发结果都相同。然后就是要找一种能得到最优解的走法,显然走每条边2次是最优的,那怎么样构造出走法呢?其实只要按照这些点的DFS序顺序走下去,最后走回第一个点即可。因为对于涉及到的每条边,只下去一次再上来一次,所以这个肯定最优。那么我们每次插入或删除一个点时,实际上只影响到它在DFS序中相邻的两个点之间的贡献,那么就用新的贡献替换旧的贡献,因为要求两点间的距离,用倍增求出即可。至于找到在当前点集中DFS序相邻的点,可以用set的lower_bound和upper_bound函数解决。
学了这么久C++,居然现在才会用set,除了常数大一点还真是好用啊……
以下是本人代码:

#include <bits/stdc++.h>
#define ll long long
using namespace std;
int n,m,first[100010]={0},tot=0,fa[100010][21],dep[100010];
int pos[100010],r[100010],tim=0;
ll dis[100010];
set<int> S;
set<int>::iterator it=S.begin();
struct edge {int v,next;ll w;} e[200010];
bool vis[100010]={0};

void insert(int a,int b,ll w)
{
    e[++tot].v=b,e[tot].w=w,e[tot].next=first[a],first[a]=tot;
}

void dfs(int v)
{
    pos[v]=++tim;
    r[tim]=v;
    for(int i=first[v];i;i=e[i].next)
        if (e[i].v!=fa[v][0])
        {
            dep[e[i].v]=dep[v]+1;
            fa[e[i].v][0]=v;
            dis[e[i].v]=dis[v]+e[i].w;
            dfs(e[i].v);
        }
}

void findlr(int x,int &l,int &r)
{
    it=S.lower_bound(x);
    if (it==S.begin()) it=S.end(),it--;
    else it--;
    l=*it;
    it=S.upper_bound(x);
    if (it==S.end()) it=S.begin();
    r=*it;
}

int lca(int x,int y)
{
    if (dep[x]<dep[y]) swap(x,y);
    for(int i=20;i>=0;i--)
        if (dep[fa[x][i]]>=dep[y]) x=fa[x][i];
    if (x==y) return x;
    for(int i=20;i>=0;i--)
        if (fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
    return fa[x][0];
}

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<n;i++)
    {
        int x,y;
        ll z;
        scanf("%d%d%lld",&x,&y,&z);
        insert(x,y,z),insert(y,x,z);
    }

    fa[1][0]=dep[1]=0;dep[0]=-1;
    dfs(1);
    for(int i=1;i<=20;i++)
        for(int j=1;j<=n;j++)
            fa[j][i]=fa[fa[j][i-1]][i-1];

    ll ans=0;
    for(int i=1;i<=m;i++)
    {
        int x,px,py,g;
        scanf("%d",&x);
        if (!vis[x])
        {
            vis[x]=1;
            S.insert(pos[x]);
            findlr(pos[x],px,py);
            ans-=dis[r[px]]+dis[r[py]]-(dis[lca(r[px],r[py])]<<1);
            ans+=dis[r[px]]+dis[x]-(dis[lca(r[px],x)]<<1);
            ans+=dis[r[py]]+dis[x]-(dis[lca(r[py],x)]<<1);
        }
        else
        {
            vis[x]=0;
            findlr(pos[x],px,py);
            ans+=dis[r[px]]+dis[r[py]]-(dis[lca(r[px],r[py])]<<1);
            ans-=dis[r[px]]+dis[x]-(dis[lca(r[px],x)]<<1);
            ans-=dis[r[py]]+dis[x]-(dis[lca(r[py],x)]<<1);
            S.erase(pos[x]);
        }
        printf("%lld
",ans);
    }

    return 0;
}
原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793506.html