bzoj3991 [SDOI2015]寻宝游戏
虚树,一直在想怎么在虚树里快速插入一个节点,其实不需要。
考虑我们要求的是什么,是按dfs序排序后的相邻关键点的距离和,于是我们直接用一个set维护当前的关键点集合,并记录当前的答案,有修改就在set里插入或删除就好了。
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 #include <cmath> 6 #include <set> 7 #define N 100500 8 using namespace std; 9 int e=1,head[N]; 10 struct edge{ 11 int v,w,next; 12 }ed[N<<1]; 13 int dep[N],fa[N][22],L[N],tot,n,m; 14 bool vis[N]; 15 long long val[N]; 16 struct cmp{ 17 bool operator () (int a,int b){ 18 return L[a]<L[b]; 19 } 20 }; 21 set<int ,cmp> s; 22 set<int ,cmp> :: iterator it; 23 void push(int u,int v,int w){ 24 ed[e].v=v;ed[e].w=w; 25 ed[e].next=head[u];head[u]=e++; 26 } 27 void dfs(int x,int d){ 28 dep[x]=d;L[x]=++tot; 29 for(int i=1;(1<<i)<=d;i++) 30 fa[x][i]=fa[fa[x][i-1]][i-1]; 31 for(int i=head[x];i;i=ed[i].next){ 32 int v=ed[i].v; 33 if(v==fa[x][0])continue; 34 fa[v][0]=x;val[v]=val[x]+ed[i].w; 35 dfs(v,d+1); 36 } 37 } 38 int getlca(int x,int y){ 39 if(dep[x]<dep[y])swap(x,y); 40 for(int i=20;~i;i--) 41 if(dep[fa[x][i]]>=dep[y])x=fa[x][i]; 42 if(x==y)return x; 43 for(int i=20;~i;i--) 44 if(fa[x][i]!=fa[y][i])x=fa[x][i],y=fa[y][i]; 45 return fa[x][0]; 46 } 47 long long getdis(int x,int y){ 48 return val[x]+val[y]-2*val[getlca(x,y)]; 49 } 50 int size; 51 long long sum; 52 void work(int x,int v){ 53 int y,z; 54 it=s.find(x); 55 if(it!=s.begin())it--,y=*it; 56 else it=s.end(),it--,y=*it; 57 it=s.find(x);it++; 58 if(it!=s.end())z=*it; 59 else it=s.begin(),z=*it; 60 sum+=v*(getdis(x,y)+getdis(x,z)-getdis(y,z)); 61 } 62 void del(int x){ 63 size--;vis[x]=0; 64 if(size<2)sum=0; 65 else work(x,-1); 66 s.erase(x); 67 } 68 void add(int x){ 69 size++;vis[x]=1; 70 s.insert(x); 71 if(size<2)sum=0; 72 else work(x,1); 73 } 74 int main(){ 75 scanf("%d%d",&n,&m); 76 for(int i=1,u,v,w;i<n;i++){ 77 scanf("%d%d%d",&u,&v,&w); 78 push(u,v,w); push(v,u,w); 79 } 80 dfs(1,1); 81 int x; 82 while(m--){ 83 scanf("%d",&x); 84 if(vis[x]) del(x); 85 else add(x); 86 printf("%lld\n",sum); 87 } 88 return 0; 89 }
人生如梦亦如幻 朝如晨露暮如霞。