bzoj3991

构建虚树,每次在set中维护其前驱,后继,更新

#include<cstdio>
#include<iostream>
#include<set>
#define N 111111
#define inf 1e9
using namespace std;
set<int> st;
int n,m,k,i,x,y,z,u,l,r,f,tot,sz,now,head,id[N],pos[N],high[N],fir[N],val[N<<1],la[N<<1],ne[N<<1],fa[N][18];
long long ans,tmp,deep[N];
bool mark[N];
void ins(int x,int y,int z){la[++tot]=y;val[tot]=z;ne[tot]=fir[x];fir[x]=tot;}
void dfs(int x,int z){
    id[x]=++sz;pos[sz]=x;
    for(int i=1;i<=17;i++)fa[x][i]=fa[fa[x][i-1]][i-1];
    for(int i=fir[x];i;i=ne[i]){
        int y=la[i];
        if(y!=z){
            deep[y]=deep[x]+val[i];
            high[y]=high[x]+1;
            fa[y][0]=x;
            dfs(y,x);
        }
    }
}
int lca(int x,int y){
    if(high[x]<high[y])swap(x,y);
    int t=high[x]-high[y];
    for(int i=0;i<=17;i++)if(t&(1<<i))x=fa[x][i];
    for(int i=17;i>=0;i--)if(fa[x][i]!=fa[y][i]){x=fa[x][i];y=fa[y][i];}
    if(x==y)return x;else return fa[x][0];
}
long long dis(int x,int y){return deep[x]+deep[y]-2*deep[lca(x,y)];}
int main(){
    scanf("%d%d",&n,&m);
    for(i=1;i<n;i++)scanf("%d%d%d",&x,&y,&z),ins(x,y,z),ins(y,x,z);
    dfs(1,0);st.insert(inf);st.insert(-inf);
    while(m--){
        scanf("%d",&x);
        if(mark[x])st.erase(id[x]),f=-1;
        else st.insert(id[x]),f=1;
        mark[x]^=1;
        int l=*--st.lower_bound(id[x]),r=*st.upper_bound(id[x]);
        if(r!=inf)ans+=f*dis(x,pos[r]);
        if(l!=-inf)ans+=f*dis(x,pos[l]);
        if(l!=-inf&&r!=inf)ans-=f*dis(pos[l],pos[r]);
        if(st.size()!=2)tmp=dis(pos[*st.upper_bound(-inf)],pos[*--st.lower_bound(inf)]);else tmp=0;
        printf("%lld\n",ans+tmp);
    }
}

 

posted @ 2018-07-02 07:49  lnyzo  阅读(183)  评论(0编辑  收藏  举报