bzoj3991: [SDOI2015]寻宝游戏
思路:将关键点按dfs序排序,然后显然就是dfs序中相邻的两个点的距离之和加上最后一个点到第一点的距离(YY一下很显然),动态维护就用splay就好了(我是一个不会用set的蒟蒻。。。。。)
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; #define maxn 100005 int n,m,tot,deg,l,cnt; int now[maxn],pre[2*maxn],son[2*maxn],val[2*maxn],dep[maxn],dfn[maxn]; int f[maxn][21]; long long ans,dis[maxn]; bool bo[maxn]; inline int read(){ int x=0;char ch=getchar(); for (;ch<'0'||ch>'9';ch=getchar()); for (;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; return x; } void add(int a,int b,int c){ son[++tot]=b; pre[tot]=now[a]; now[a]=tot; val[tot]=c; } void link(int a,int b,int c){ add(a,b,c),add(b,a,c); } void dfs(int x,int fa){ dep[x]=dep[fa]+1,dfn[x]=++deg; for (int i=1;i<=l;i++) f[x][i]=f[f[x][i-1]][i-1]; for (int p=now[x];p;p=pre[p]) if (son[p]!=fa) f[son[p]][0]=x,dis[son[p]]=dis[x]+val[p],dfs(son[p],x); } int lca(int a,int b){ if (dep[a]<dep[b]) swap(a,b);int x=dep[a]-dep[b],t=0; for (;x;x>>=1,t++) if (x&1) a=f[a][t]; if (a==b) return a;t=l; for (;f[a][0]!=f[b][0];){ for (;f[a][t]==f[b][t];t--); a=f[a][t],b=f[b][t]; } return f[a][0]; } struct splay_tree{ int ch[maxn][2],fa[maxn],note[maxn],val[maxn],pos[maxn],root,tot; void rotate(int x){ int y=fa[x],z=fa[y],bo=note[x],bo1=note[y]; ch[y][bo]=ch[x][bo^1],fa[ch[x][bo^1]]=y; ch[x][bo^1]=y,fa[y]=x; fa[x]=z;if (bo1!=2) ch[z][bo1]=x; note[x]=bo1,note[y]=bo^1,note[ch[y][bo]]=bo; } void splay(int x){ while (note[x]!=2){ if (note[x]==note[fa[x]]) rotate(fa[x]); rotate(x); } root=x; } void insert(int x,int v,int p){ int y; while (1){ y=ch[x][val[x]<v]; if (!y){ y=++tot; val[y]=v,pos[y]=p; if (x) note[y]=val[x]<v;else note[y]=2; fa[y]=x,ch[y][0]=ch[y][1]=0; if (x) ch[x][note[y]]=y; break; } x=y; } splay(y); } int find(int v){ int x=root; while (1){ if (val[x]==v) return splay(x),x; if (val[x]<v) x=ch[x][1];else x=ch[x][0]; } } int pre(int x){ splay(x);x=ch[x][0]; while (ch[x][1]) x=ch[x][1]; return x; } int suc(int x){ splay(x);x=ch[x][1]; while (ch[x][0]) x=ch[x][0]; return x; } int getmin(){int x=root;while (ch[x][0]) x=ch[x][0];return x;} int getmax(){int x=root;while (ch[x][1]) x=ch[x][1];return x;} void del(int v){ int x=find(v);int y=suc(x),z=ch[x][0]; if (!y){ if (!z){root=0;return;} fa[z]=0,note[z]=2,root=z;return; } fa[ch[x][1]]=0,note[ch[x][1]]=2,splay(y); fa[z]=y,ch[y][0]=z,root=y; } }S; int main(){ n=read(),m=read();l=log2(n); for (int i=1,a,b,c;i<n;i++) a=read(),b=read(),c=read(),link(a,b,c); dfs(1,0); while (m--){ int x=read();bo[x]^=1; if (bo[x]) S.insert(S.root,dfn[x],x),cnt++; int a=S.pre(S.find(dfn[x])),b=S.suc(S.find(dfn[x])); if (!a) a=S.getmax();if (!b) b=S.getmin(); a=S.pos[a],b=S.pos[b]; if (!bo[x]) S.del(dfn[x]),cnt--; if (cnt<=1){puts("0"),ans=0;continue;} ans+=(bo[x]?1:-1)*(dis[a]+dis[x]-2*dis[lca(a,x)]); ans+=(bo[x]?1:-1)*(dis[x]+dis[b]-2*dis[lca(b,x)]); ans+=(bo[x]?-1:1)*(dis[a]+dis[b]-2*dis[lca(a,b)]); printf("%lld\n",ans); } return 0; }