[BZOJ3991][SDOI2015]寻宝游戏

睡前写题解。此题Pascal党有难度max的buff……毕竟C++有set这种黑科技,P党只好手写平衡树。然而这还不是最主要的,最大的代码难点在于此题有奇怪的边界处理,加了一堆特判,用封好的set大概会清晰很多。

脑补一下就会发现答案就是所有被选中的点所构成的虚树的边权和的两倍,走路的过程就是在虚树上dfs的过程。这样我们可以把原树先dfs一遍,在虚树中dfs的时候访问关键点的先后顺序与原树中dfs是一致的,这样我们对于一些关键点可以把它们按照dfs序从前往后排,由第一个点开始走,一个一个往后依次走,答案就是这个序列中所有相邻两点在树上的距离之和,别忘了从最后一个点还要走回第一个点(可以把这个序列想象成环形的),这个序列用平衡树维护就好了,需要注意的是在加入/删除点的时候点如果没有后继那么后继算第一个点,如果没有前件那么前件算最后一个点。两点间的距离lca搞一搞。个人觉得代码实现才是难度最大的,代码写得丑QAQ

  1 program bzoj3991;
  2 const maxn=100010;
  3 var dfn,last,fa:array[0..maxn] of longint;
  4     dep:array[0..maxn] of int64;
  5     dfsseq:array[0..2*maxn] of longint;
  6     st:array[0..2*maxn,0..20] of longint; //according to dep
  7     trea:array[0..maxn] of boolean;
  8     ed:array[0..maxn*2] of record o,next,l:longint; end;
  9     tree:array[0..maxn] of record fa,key,w:longint; son:array[0..1] of longint;end;
 10     //according to dfn
 11     log:array[0..2*maxn] of longint;
 12     ans:int64;
 13     n,m,i,tot,t1,t2,t,u,v,w:longint;
 14 procedure rotate(x,dir:longint);
 15 var f,s:longint;
 16 begin
 17   f:=tree[x].fa;
 18   s:=tree[x].son[dir];
 19   tree[x].son[dir]:=tree[s].son[1-dir];
 20   tree[tree[s].son[1-dir]].fa:=x;
 21   tree[s].son[1-dir]:=x;
 22   tree[x].fa:=s;
 23   tree[s].fa:=f;
 24   if tree[f].son[0]=x then tree[f].son[0]:=s
 25     else tree[f].son[1]:=s;
 26 end;
 27 function min(x,y:longint):longint;
 28 begin
 29   if dep[x]<dep[y] then exit(x) else exit(y);
 30 end;
 31 procedure add(u,v,w:longint);
 32 begin
 33   inc(tot);
 34   ed[tot].next:=last[u];
 35   last[u]:=tot;
 36   ed[tot].o:=v;
 37   ed[tot].l:=w;
 38 end;
 39 procedure dfs(x:Longint;d:int64);
 40 var i:longint;
 41 begin
 42   inc(tot);
 43   dfn[x]:=tot;
 44   dep[x]:=d;
 45   dfsseq[tot]:=x;
 46   i:=last[x];
 47   while i<>0 do
 48     begin
 49       if fa[x]<>ed[i].o then
 50         begin
 51           fa[ed[i].o]:=x;
 52           dfs(ed[i].o,d+ed[i].l);
 53           inc(tot);
 54           dfsseq[tot]:=x;
 55         end;
 56       i:=ed[i].next;
 57     end;
 58 end;
 59 function suc(x,p:longint):longint;
 60 var t:longint;
 61 begin
 62   if x=0 then exit(0);
 63   if dfn[tree[x].key]<=dfn[p] then exit(suc(tree[x].son[1],p))
 64     else begin t:=suc(tree[x].son[0],p); if t=0 then exit(x) else exit(t); end;
 65 end;
 66 function pre(x,p:longint):longint;
 67 var t:longint;
 68 begin
 69   if x=0 then exit(0);
 70   if dfn[tree[x].key]>=dfn[p] then exit(pre(tree[x].son[0],p))
 71     else begin t:=pre(tree[x].son[1],p); if t=0 then exit(x) else exit(t); end;
 72 end;
 73 function findmin:longint;
 74 var i:longint;
 75 begin
 76   i:=tree[1].son[1];
 77   while tree[i].son[0]<>0 do i:=tree[i].son[0];
 78   exit(i);
 79 end;
 80 function findmax:longint;
 81 var i:longint;
 82 begin
 83   i:=1;
 84   while tree[i].son[1]<>0 do i:=tree[i].son[1];
 85   exit(i);
 86 end;
 87 procedure join(x:longint);
 88 var i:Longint;
 89 begin
 90   i:=1;
 91   while tree[i].son[ord(dfn[tree[x].key]>dfn[tree[i].key])]<>0 do
 92     i:=tree[i].son[ord(dfn[tree[x].key]>dfn[tree[i].key])];
 93   tree[i].son[ord(dfn[tree[x].key]>dfn[tree[i].key])]:=x;
 94   tree[x].fa:=i;
 95   tree[x].w:=random(100000000);
 96   while tree[x].w<tree[tree[x].fa].w do
 97     if tree[tree[x].fa].son[1]=x then rotate(tree[x].fa,1)
 98       else rotate(tree[x].fa,0);
 99 end;
100 function find(x:longint):longint;
101 var i:longint;
102 begin
103   i:=1;
104   while tree[i].key<>x do
105     i:=tree[i].son[ord(dfn[x]>dfn[tree[i].key])];
106   exit(i);
107 end;
108 procedure del(x:longint);
109 begin
110   while (tree[x].son[0]<>0)or(tree[x].son[1]<>0) do
111     if tree[tree[x].son[0]].w<tree[tree[x].son[1]].w then rotate(x,0)
112       else rotate(x,1);
113   if tree[tree[x].fa].son[0]=x then tree[tree[x].fa].son[0]:=0
114     else tree[tree[x].fa].son[1]:=0;
115   tree[x].fa:=0;
116 end;
117 procedure STprework;
118 var i,j:longint;
119 begin
120   log[1]:=0;
121   for i:=2 to tot do
122     if i and (i-1)=0 then log[i]:=log[i-1]+1
123       else log[i]:=log[i-1];
124   for i:=1 to tot do
125     st[i,0]:=dfsseq[i];
126   for i:=1 to log[tot] do
127     for j:=1 to tot do
128         if j+1 shl (i-1)<=tot then st[j,i]:=min(st[j,i-1],st[j+1 shl (i-1),i-1])
129           else st[j,i]:=st[j,i-1];
130 end;
131 function dis(x,y:longint):int64;
132 var lca:longint;
133 begin
134   if dfn[x]>dfn[y] then
135     begin
136       lca:=x;
137       x:=y;
138       y:=lca;
139     end;
140   lca:=min(st[dfn[x],log[dfn[y]-dfn[x]+1]],st[dfn[y]-1 shl log[dfn[y]-dfn[x]+1]+1,log[dfn[y]-dfn[x]+1]]);
141   exit(dep[x]+dep[y]-2*dep[lca]);
142 end;
143 begin
144   randomize;
145   fillchar(last,sizeof(last),0);
146   readln(n,m);
147   tot:=0;
148   for i:=1 to n-1 do
149     begin
150       readln(u,v,w);
151       add(u,v,w);
152       add(v,u,w);
153     end;
154   tot:=0;
155   dfs(1,0);
156   STprework;
157   tree[1].key:=0;
158   tree[1].w:=-maxlongint;
159   tree[0].w:=maxlongint;
160   dfn[0]:=0;
161   tot:=1;
162   ans:=0;
163   fillchar(trea,sizeof(trea),0);
164   for i:=1 to m do
165     begin
166       readln(t);
167       if trea[t] then
168         begin
169           trea[t]:=false;
170           t1:=pre(tree[1].son[1],t);
171           t2:=suc(tree[1].son[1],t);
172           if t1=0 then t1:=findmax;
173           if t2=0 then t2:=findmin;
174           if (t1<>0)and(t2<>0) then
175             ans:=ans-dis(t,tree[t1].key)-dis(t,tree[t2].key)+dis(tree[t1].key,tree[t2].key);
176           del(find(t));
177           writeln(ans);
178         end
179           else
180             begin
181               trea[t]:=true;
182               inc(tot);
183               tree[tot].key:=t;
184               join(tot);
185               t1:=pre(tree[1].son[1],t);
186               t2:=suc(tree[1].son[1],t);
187               if t1=0 then t1:=findmax;
188               if t2=0 then t2:=findmin;
189               if (t1<>0)and(t2<>0) then
190                 ans:=ans+dis(t,tree[t1].key)+dis(t,tree[t2].key)-dis(tree[t1].key,tree[t2].key);
191               writeln(ans);
192             end;
193     end;
194 end.
时间: 2024-10-20 14:26:40

[BZOJ3991][SDOI2015]寻宝游戏的相关文章

[bzoj3991][SDOI2015]寻宝游戏_树链的并_倍增lca_平衡树set

寻宝游戏 bzoj-3991 SDOI-2015 题目大意:题目链接. 注释:略. 想法:我们发现如果给定了一些点有宝物的话那么答案就是树链的并. 树链的并的求法就是把所有点按照$dfs$序排序然后相加再减去相邻之间的$lca$. 故此我们按照$dfs$序维护一个平衡树. 每次往里插入节点即可. 实时用$lca$更新答案,复杂度$O(nlogn)$. Code: #include <iostream> #include <cstdio> #include <cstring&g

【dfs序】【set】bzoj3991 [Sdoi2015]寻宝游戏

在考试代码的基础上稍微改改就a了……当时为什么不稍微多想想…… 插入/删除一个新节点时就把其dfn插入set. 当前的答案就是dfn上相邻的两两节点的距离和,再加上首尾节点的距离. 比较显然?不会证明…… 貌似叫“虚树”? #include<cstdio> #include<set> using namespace std; #define N 100001 typedef long long ll; set<int>S; typedef set<int>:

【BZOJ3991】[SDOI2015]寻宝游戏 树链的并+set

[BZOJ3991][SDOI2015]寻宝游戏 Description 小B最近正在玩一个寻宝游戏,这个游戏的地图中有N个村庄和N-1条道路,并且任何两个村庄之间有且仅有一条路径可达.游戏开始时,玩家可以任意选择一个村庄,瞬间转移到这个村庄,然后可以任意在地图的道路上行走,若走到某个村庄中有宝物,则视为找到该村庄内的宝物,直到找到所有宝物并返回到最初转移到的村庄为止.小B希望评测一下这个游戏的难度,因此他需要知道玩家找到所有宝物需要行走的最短路程.但是这个游戏中宝物经常变化,有时某个村庄中会突

【BZOJ 3991】 [SDOI2015]寻宝游戏

3991: [SDOI2015]寻宝游戏 Time Limit: 40 Sec Memory Limit: 128 MB Submit: 251 Solved: 137 [Submit][Status][Discuss] Description 小B最近正在玩一个寻宝游戏,这个游戏的地图中有N个村庄和N-1条道路,并且任何两个村庄之间有且仅有一条路径可达.游戏开始时,玩家可以任意选择一个村庄,瞬间转移到这个村庄,然后可以任意在地图的道路上行走,若走到某个村庄中有宝物,则视为找到该村庄内的宝物,直

P3320 [SDOI2015]寻宝游戏

题目 P3320 [SDOI2015]寻宝游戏 做法 很巧妙的一种思路,懂了之后觉得大水题 首先要知道:在一棵树上标记一些点,然后从任意一点出发,遍历所有的的最小路径为\(dfs\)序从小到大遍历 那就把点丢到\(set\)里面,然后找\(dfs\)的前驱与后继计算路径就好了 其实也有点虚树的思想,只管标记的这几个点 My complete code #include<cstdio> #include<iostream> #include<algorithm> #inc

异象石/[SDOI2015]寻宝游戏

AcWing 异象石 洛咕 寻宝游戏 题意:Adera是Microsoft应用商店中的一款解谜游戏. 异象石是进入Adera中异时空的引导物,在Adera的异时空中有一张地图. 这张地图上有\(N(N<=1e5)\)个点,有\(N-1\)条双向边把它们连通起来. 起初地图上没有任何异象石,在接下来的\(M(M<=1e5)\)个时刻中,每个时刻会发生以下三种类型的事件之一: 地图的某个点上出现了异象石(已经出现的不会再次出现); 地图某个点上的异象石被摧毁(不会摧毁没有异象石的点); 向玩家询问

bzoj 3991: [SDOI2015]寻宝游戏

Description 小B最近正在玩一个寻宝游戏,这个游戏的地图中有N个村庄和N-1条道路,并且任何两个村庄之间有且仅有一条路径可达.游戏开始时,玩家可以任意选择一个村庄,瞬间转移到这个村庄,然后可以任意在地图的道路上行走,若走到某个村庄中有宝物,则视为找到该村庄内的宝物,直到找到所有宝物并返回到最初转移到的村庄为止.小B希望评测一下这个游戏的难度,因此他需要知道玩家找到所有宝物需要行走的最短路程.但是这个游戏中宝物经常变化,有时某个村庄中会突然出现宝物,有时某个村庄内的宝物会突然消失,因此小

Luogu P3320 [SDOI2015]寻宝游戏 / 异象石 【LCA/set】

期末考试结束祭! 在期末考试前最后一发的测试中,异象石作为第二道题目出现QAQ.虽然知道是LCA图论,但还是敲不出来QAQ. 花了两天竞赛课的时间搞懂(逃 异象石(stone.pas/c/cpp)题目描述Adera 是 Microsoft 应用商店中的一款解谜游戏.异象石是进入 Adera 中异时空的引导物,在 Adera 的异时空中有一张地图.这张地图上有 N 个点,有 N-1 条双向边把它们连通起来.起初地图上没有任何异象石,在接下来的 M个时刻中,每个时刻会发生以下三种类型的事件之一:1.

[SDOI2015]寻宝游戏

寻宝游戏 对于dfs序的理解.好题!题目传送门 Description 小B最近正在玩一个寻宝游戏,这个游戏的地图中有N个村庄和N-1条道路,并且任何两个村庄之间有且仅有一条路径可达.游戏开始时,玩家可以任意选择一个村庄,瞬间转移到这个村庄,然后可以任意在地图的道路上行走,若走到某个村庄中有宝物,则视为找到该村庄内的宝物,直到找到所有宝物并返回到最初转移到的村庄为止.小B希望评测一下这个游戏的难度,因此他需要知道玩家找到所有宝物需要行走的最短路程.但是这个游戏中宝物经常变化,有时某个村庄中会突然