zoukankan      html  css  js  c++  java
  • BZOJ 3991: [SDOI2015]寻宝游戏

    随便选一个点当做根,跑每个点的深度(为了求LCA)d [ u ] ,和到根节点的距离(为了更新答案) l [ u ]

    我们发现,由关键点和他们的LCA构成的虚树(其实就是忽略其他节点),由于还要回到原点,所以相当于是树的所有边权的2倍

    怎么求?对于每一次标记,将所有的标记了的点按时间戳排序,那么答案就是一、二两点之间的距离,二、三点之间距离。。。。最后一个点和第一个点之间的距离的总和;

    而两点之间的距离等于 l [ u ] + l [ v ] - 2 * l [ lca ( u , v ) ]

    维护这些点时可以用set

    #include<cstdio>
    #include<iostream>
    #include<set>
    #include<cmath>
    #define getchar() *S++
    #define ll long long 
    #define R register int
    const int N=100010,Inf=0x3f3f3f3f;
    char RR[100000005],*S=RR;
    using namespace std;
    inline int g() {
        R ret=0; register char ch; while(!isdigit(ch=getchar())); 
        do ret=ret*10+(ch^48); while(isdigit(ch=getchar())); return ret;
    }
    int n,m,num,cnt;
    int vr[N<<1],nxt[N<<1],w[N<<1],fir[N],dfn[N],rw[N],d[N],f[N][18];
    set<int>s;
    set<int>::iterator it;
    ll ans,l[N];
    bool vis[N];
    inline void add(int u,int v,int ww) {vr[++cnt]=v,w[cnt]=ww,nxt[cnt]=fir[u],fir[u]=cnt;}
    void dfs(int u) { dfn[u]=++num,rw[num]=u;
        for(R i=fir[u];i;i=nxt[i]) { R v=vr[i];
            if(d[v]) continue; d[v]=d[u]+1; l[v]=l[u]+w[i]; f[v][0]=u; R p=u;
            for(R j=0;f[p][j];++j) f[v][j+1]=f[p][j],p=f[p][j];
            dfs(v);
        }
    }
    inline int lca(int u,int v) {
        if(d[u]<d[v]) swap(u,v); R lim=log2(d[u])+1;
        for(R j=lim;j>=0;--j) if(d[f[u][j]]>=d[v]) u=f[u][j];
        if(u==v) return u;
        for(R j=lim;j>=0;--j) if(f[u][j]!=f[v][j]) u=f[u][j],v=f[v][j];
        return f[u][0];
    }
    inline ll dis(int u,int v) {return l[u]+l[v]-2*l[lca(u,v)];}
    signed main() {
        fread(RR,sizeof(RR),1,stdin);
        n=g(),m=g();
        for(R i=1,u,v,w;i<n;++i) u=g(),v=g(),w=g(),add(u,v,w),add(v,u,w);
        d[1]=1;dfs(1); 
        s.insert(-Inf),s.insert(Inf);
        for(R i=1,x;i<=m;++i) { x=g(); register long long flg; 
            if(vis[x]) s.erase(dfn[x]),flg=-1; else s.insert(dfn[x]),flg=1; vis[x]^=1;
            it=s.upper_bound(dfn[x]); R r=*it,l=*(--it); if(l>=dfn[x]) l=*(--it);
            //cout<<l<<" "<<dfn[x]<<" "<<r<<endl;
            if(l!=-Inf) ans+=flg*dis(rw[l],x); if(r!=Inf) ans+=flg*dis(x,rw[r]);
            if(l!=-Inf&&r!=Inf) ans-=flg*dis(rw[l],rw[r]); 
            register long long tmp=(s.size()>3)?dis(rw[*++s.begin()],rw[*--(--s.end())]):0;
            printf("%lld
    ",ans+tmp);
        }
    }

    2019.04.18

  • 相关阅读:
    mixin混合
    python类内部调用自己的成员函数必须加self
    合并/取消合并单元格
    pandas 显示所有的行和列
    pandas 利用openpyxl设置表格样式
    Nowcoder9983G.糖果(并查集)
    Nowcoder9983F.匹配串(思维)
    Nowcoder9983E.买礼物(链表+线段树)
    Nowcoder9983C.重力追击(暴力+少用sqrt)
    Nowcoder9983B.内卷(双指针)
  • 原文地址:https://www.cnblogs.com/Jackpei/p/10732622.html
Copyright © 2011-2022 走看看