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); } }