• BZOJ 3991: [SDOI2015]寻宝游戏 [虚树 树链的并 set]


    传送门

    题意:

    $n$个点的树,$m$次变动使得某个点有宝物或没宝物,询问每次变动后集齐所有宝物并返回原点的最小距离


    转化成有根树,求树链的并...

    两两树链求并就可以,但我们按照$dfs$序来两两求并,相邻两点深度和减去$lca$的深度

    一次只变动一个关键点,用$set$动态维护虚树($dfs$序)就好了

    并不需要建树

    注意树根不是$1$,但也不能每次减当前树根的深度,所以我们放在最后让树链的并减去树根的深度

    【15:02:56】学到一个trick,可以用一个仿函数比较$dfs$序传到$set$里,很方便

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    #include <set>
    using namespace std;
    typedef long long ll;
    const int N=1e5+5;
    inline int read(){
        char c=getchar();int x=0,f=1;
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
        return x*f;
    }
    
    int n,Q,u,v,x;
    struct Edge{
        int v,ne,w;
    }e[N<<1];
    int cnt,h[N];
    inline void ins(int u,int v,int w){
        cnt++;
        e[cnt].v=v;e[cnt].w=w;e[cnt].ne=h[u];h[u]=cnt;
        cnt++;
        e[cnt].v=u;e[cnt].w=w;e[cnt].ne=h[v];h[v]=cnt;
    }
    int dfn[N],dfc,top[N],size[N],mx[N],deep[N],fa[N];
    int pos[N];
    ll dis[N];
    void dfs(int u){
        size[u]++;
        for(int i=h[u];i;i=e[i].ne){
            int v=e[i].v;
            if(v==fa[u]) continue;
            fa[v]=u;deep[v]=deep[u]+1;
            dis[v]=dis[u]+e[i].w;
            dfs(v);
            size[u]+=size[v];
            if(size[v]>size[mx[u]]) mx[u]=v;
        }
    }
    void dfs2(int u,int anc){
        dfn[u]=++dfc;top[u]=anc;
        pos[dfc]=u;
        if(mx[u]) dfs2(mx[u],anc);
        for(int i=h[u];i;i=e[i].ne)
            if(e[i].v!=fa[u] && e[i].v!=mx[u]) dfs2(e[i].v,e[i].v);
    }
    inline int lca(int x,int y){
        if(x==0 || y==0) return 0;
        while(top[x]!=top[y]){
            if(deep[top[x]]<deep[top[y]]) swap(x,y);
            x=fa[top[x]];
        }
        return deep[x]<deep[y] ? x : y;
    }
    
    set<int> S;
    set<int>::iterator it;
    int has[N],root;
    ll chain;
    inline void ModifyRoot(){
        it=S.end();
        root=lca(pos[*S.begin()],pos[*(--it)]);
    }
    void vtrAdd(int x){//printf("Add %d %d
    ",x,dfn[x]);
        it=S.insert(dfn[x]).first;
    
        chain+=dis[x];
        int a=0,b=0;
        if( it!=S.begin() ) a=pos[*(--it)++];
        if( (++it)!=S.end() ) b=pos[*it];
        //printf("a b %d %d
    ",a,b);
        chain+=dis[ lca(a,b) ];
        chain-=dis[ lca(a,x) ] + dis[ lca(b,x) ];
    }
    void vtrDel(int x){//printf("Del %d %d
    ",x,dfn[x]);
        chain-=dis[x];
        it=S.find(dfn[x]);
        int a=0,b=0;
        if(it!=S.begin()) a=pos[*(--it)++];
        if((++it)!=S.end()) b=pos[*it];
        chain+=dis[ lca(a,x) ] + dis[ lca(b,x) ];
        chain-=dis[ lca(a,b) ];
        S.erase(dfn[x]);
        ModifyRoot();
    }
    
    int main(){
        freopen("in","r",stdin);
        n=read();Q=read();
        for(int i=1;i<n;i++) u=read(),v=read(),ins(u,v,read());
        dfs(1);dfs2(1,1);
        //for(int i=1;i<=n;i++) printf("%d ",dfn[i]);puts("");
        while(Q--){
            x=read(); has[x]^=1;
            if(has[x]) vtrAdd(x);
            else vtrDel(x);
            ModifyRoot();
            printf("%lld
    ",(chain-dis[root])<<1);
        }
    }
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    #include <set>
    using namespace std;
    typedef long long ll;
    const int N=1e5+5;
    inline int read(){
        char c=getchar();int x=0,f=1;
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
        return x*f;
    }
    
    int n,Q,u,v,x;
    struct Edge{
        int v,ne,w;
    }e[N<<1];
    int cnt,h[N];
    inline void ins(int u,int v,int w){
        cnt++;
        e[cnt].v=v;e[cnt].w=w;e[cnt].ne=h[u];h[u]=cnt;
        cnt++;
        e[cnt].v=u;e[cnt].w=w;e[cnt].ne=h[v];h[v]=cnt;
    }
    int dfn[N],dfc,top[N],size[N],mx[N],deep[N],fa[N];
    ll dis[N];
    void dfs(int u){
        size[u]++;
        for(int i=h[u];i;i=e[i].ne){
            int v=e[i].v;
            if(v==fa[u]) continue;
            fa[v]=u;deep[v]=deep[u]+1;
            dis[v]=dis[u]+e[i].w;
            dfs(v);
            size[u]+=size[v];
            if(size[v]>size[mx[u]]) mx[u]=v;
        }
    }
    void dfs2(int u,int anc){
        dfn[u]=++dfc;top[u]=anc;
        if(mx[u]) dfs2(mx[u],anc);
        for(int i=h[u];i;i=e[i].ne)
            if(e[i].v!=fa[u] && e[i].v!=mx[u]) dfs2(e[i].v,e[i].v);
    }
    inline int lca(int x,int y){
        if(x==0 || y==0) return 0;
        while(top[x]!=top[y]){
            if(deep[top[x]]<deep[top[y]]) swap(x,y);
            x=fa[top[x]];
        }
        return deep[x]<deep[y] ? x : y;
    }
    struct DFSN{
        bool operator ()(int x,int y){return dfn[x]<dfn[y];}
    };
    set<int,DFSN> S;
    set<int,DFSN>::iterator it;
    int has[N],root;
    ll chain;
    inline void ModifyRoot(){
        it=S.end();
        root=lca(*S.begin(),*(--it));
    }
    void vtrAdd(int x){//printf("Add %d %d
    ",x,dfn[x]);
        it=S.insert(x).first;
    
        chain+=dis[x];
        int a=0,b=0;
        if( it!=S.begin() ) a=*(--it)++;
        if( (++it)!=S.end() ) b=*it;
        //printf("a b %d %d
    ",a,b);
        chain+=dis[ lca(a,b) ];
        chain-=dis[ lca(a,x) ] + dis[ lca(b,x) ];
    }
    void vtrDel(int x){//printf("Del %d %d
    ",x,dfn[x]);
        chain-=dis[x];
        it=S.find(x);
        int a=0,b=0;
        if(it!=S.begin()) a=*(--it)++;
        if((++it)!=S.end()) b=*it;
        chain+=dis[ lca(a,x) ] + dis[ lca(b,x) ];
        chain-=dis[ lca(a,b) ];
        S.erase(x);
        ModifyRoot();
    }
    
    int main(){
        freopen("in","r",stdin);
        n=read();Q=read();
        for(int i=1;i<n;i++) u=read(),v=read(),ins(u,v,read());
        dfs(1);dfs2(1,1);
        //for(int i=1;i<=n;i++) printf("%d ",dfn[i]);puts("");
        while(Q--){
            x=read(); has[x]^=1;
            if(has[x]) vtrAdd(x);
            else vtrDel(x);
            ModifyRoot();
            printf("%lld
    ",(chain-dis[root])<<1);
        }
    }
  • 相关阅读:
    freeswitch与外部网关链接
    dojo中DateTextBox日期格式yyyy-MM-dd转化为数据库中yyyyMMdd
    dojo中取DateTextBox中的值两种方法
    视频编码与封装方式详解
    音频编码汇总
    FusionCharts 3D双柱状图
    FusionCharts 2D双柱状图
    利用merge优化
    FusionCharts 2D条状图
    全表扫描出现db file sequential read
  • 原文地址:https://www.cnblogs.com/candy99/p/6525631.html
Copyright © 2020-2023  润新知