【BZOJ】【3991】【SDOI2015】寻宝游戏

dfs序



  我哭啊……这题在考试的时候(我不是山东的,CH大法吼)没想出来……只写了50分的暴力QAQ

  而且苦逼的写的比正解还长……我骗点分容易吗QAQ

  骗分做法:

  1.$n,m\leq 1000$: 直接找一个关键点做根进行深搜,算出其他关键点都与root连通的最小边权和,再×2

  2.一条链的情况:用set维护序列中哪些点选了,然后ans=(sum[tail]-sum[head])*2; 其中sum[i]表示从序列首到第 i 个的边长之和……嗯就是前缀和优化一下= =取首和尾这一段的Len之和

  3.保证第一次一定变动1号村庄,且以后1不再变动:以1为根,每次update(x),将从x到1的所有边更新一遍,看有多少个点需要经过它,如果是新加的边就在ans中加进来,如果这次删点后这条边无用了,就在ans中减去

  以上就是50分的骗分做法……写起来倒是不难(正解写起来更简单QAQ)

  1 //Huce #4 B
  2 #include<set>
  3 #include<vector>
  4 #include<cstdio>
  5 #include<cstdlib>
  6 #include<cstring>
  7 #include<iostream>
  8 #include<algorithm>
  9 #define rep(i,n) for(int i=0;i<n;++i)
 10 #define F(i,j,n) for(int i=j;i<=n;++i)
 11 #define D(i,j,n) for(int i=j;i>=n;--i)
 12 using namespace std;
 13
 14 int getint(){
 15     int v=0,sign=1; char ch=getchar();
 16     while(ch<‘0‘||ch>‘9‘) {if (ch==‘-‘) sign=-1; ch=getchar();}
 17     while(ch>=‘0‘&&ch<=‘9‘) {v=v*10+ch-‘0‘; ch=getchar();}
 18     return v*sign;
 19 }
 20 typedef long long LL;
 21 const int N=100010,INF=~0u>>2;
 22 /*******************tamplate********************/
 23 int head[N],to[N<<1],next[N<<1],len[N<<1],cnt;
 24 void add(int x,int y,int z){
 25     to[++cnt]=y; next[cnt]=head[x]; len[cnt]=z; head[x]=cnt;
 26     to[++cnt]=x; next[cnt]=head[y]; len[cnt]=z; head[y]=cnt;
 27 }
 28 /*********************edge**********************/
 29 int n,m,du[N];
 30 bool sign[N],vis[N];
 31
 32 namespace work1{
 33     LL ans;
 34     bool dfs(int x){
 35         bool tmp=sign[x];
 36         vis[x]=1;
 37         for(int i=head[x];i;i=next[i]) if(!vis[to[i]]){
 38             if (dfs(to[i])){
 39                 ans+=len[i];
 40                 tmp=1;
 41             }
 42         }
 43         return tmp;
 44     }
 45     LL solve(){
 46         ans=0;
 47         memset(vis,0,sizeof vis);
 48         F(i,1,n) if (sign[i]){
 49             dfs(i);
 50             return ans;
 51         }
 52     }
 53     void work1(){
 54         int x;
 55         F(i,1,m){
 56             x=getint(); sign[x]^=1;
 57             printf("%lld\n",solve()*2);
 58         }
 59     }
 60 }
 61 namespace work2{
 62     int a[N],tot,num[N];
 63     LL sum[N];
 64     void dfs(int x,int l){
 65         vis[x]=1;
 66         a[++tot]=x;
 67         sum[tot]=sum[tot-1]+l;
 68         num[x]=tot;
 69         for(int i=head[x];i;i=next[i])
 70             if (!vis[to[i]])
 71                 dfs(to[i],len[i]);
 72     }
 73     set<int>s;
 74     set<int>::iterator it;
 75     void work2(){
 76         F(i,1,n) if (du[i]==1){
 77             dfs(i,0);
 78             break;
 79         }
 80 //        F(i,1,tot) printf("%d ",a[i]);puts("");
 81         int x;
 82         F(i,1,m){
 83             x=getint();
 84             sign[x]^=1;
 85             if (sign[x]) s.insert(num[x]);
 86             else{
 87                 it=s.find(num[x]);
 88                 s.erase(it);
 89             }
 90             it=s.end(); it--;
 91 //            printf("%d %d\n",*s.begin(),*s.rbegin());
 92             printf("%lld\n",(sum[*s.rbegin()]-sum[*s.begin()])*2);
 93         }
 94     }
 95 }
 96 namespace work3{
 97     int fa[N],num[N],dis[N];
 98     LL ans;
 99     bool vis[N];
100     void dfs(int x){
101         vis[x]=1;
102         for(int i=head[x];i;i=next[i])
103             if (!vis[to[i]]){
104                 fa[to[i]]=x;
105                 dis[to[i]]=len[i];
106                 dfs(to[i]);
107             }
108     }
109     void update(int x,int v){
110         if (x==1) return;
111         if (v==1){
112             num[x]++;
113             if (num[x]==1) ans+=dis[x];
114         }else{
115             num[x]--;
116             if (num[x]==0) ans-=dis[x];
117         }
118         update(fa[x],v);
119     }
120     void work3(){
121         int x;
122         memset(vis,0,sizeof vis);
123         dfs(1);
124 //        F(i,1,n) printf("%d ",dis[i]); puts("");
125         F(i,1,m){
126             x=getint(); sign[x]^=1;
127             update(x,sign[x]?1:-1);
128             printf("%lld\n",ans*2);
129         }
130     }
131 }
132 int main(){
133 #ifndef ONLINE_JUDGE
134     freopen("B.in","r",stdin);
135 //    freopen("output.txt","w",stdout);
136 #endif
137     n=getint(); m=getint();
138     int x,y,z,mx=0;
139     F(i,2,n){
140         x=getint(); y=getint(); z=getint();
141         add(x,y,z);
142         du[x]++; du[y]++;
143         mx=max(mx,max(du[x],du[y]));
144     }
145     if (n<=1000) work1::work1();
146     else if (mx==2)    work2::work2();
147     else
148         work3::work3();
149     return 0;
150 }

50分暴力

  其实从骗分2的做法再仔细想想就可以推广到整棵树的情况了:将整个树的dfs序搞出来,那么$ans=\sum dfs序中相邻两点的dist$,其中第一个点与最后一个点视为相邻。

  然后用set维护一下点之间的相邻状态(按dfs序排序后,其实就跟上面链的感觉差不多),更新答案就可以了(dist(i,j)可以用从根到 i ,j 以及LCA(i,j)的距离O(logn)算出来)

  QAQ我还是too young too naive

  1 /**************************************************************
  2     Problem: 3991
  3     User: Tunix
  4     Language: C++
  5     Result: Accepted
  6     Time:7188 ms
  7     Memory:19016 kb
  8 ****************************************************************/
  9
 10 //Huce #4 B
 11 #include<set>
 12 #include<vector>
 13 #include<cstdio>
 14 #include<cstdlib>
 15 #include<cstring>
 16 #include<iostream>
 17 #include<algorithm>
 18 #define rep(i,n) for(int i=0;i<n;++i)
 19 #define F(i,j,n) for(int i=j;i<=n;++i)
 20 #define D(i,j,n) for(int i=j;i>=n;--i)
 21 using namespace std;
 22
 23 int getint(){
 24     int v=0,sign=1; char ch=getchar();
 25     while(ch<‘0‘||ch>‘9‘) {if (ch==‘-‘) sign=-1; ch=getchar();}
 26     while(ch>=‘0‘&&ch<=‘9‘) {v=v*10+ch-‘0‘; ch=getchar();}
 27     return v*sign;
 28 }
 29 typedef long long LL;
 30 const int N=100010,INF=~0u>>2;
 31 /*******************tamplate********************/
 32 int head[N],to[N<<1],next[N<<1],len[N<<1],cnt;
 33 void add(int x,int y,int z){
 34     to[++cnt]=y; next[cnt]=head[x]; len[cnt]=z; head[x]=cnt;
 35     to[++cnt]=x; next[cnt]=head[y]; len[cnt]=z; head[y]=cnt;
 36 }
 37 /*********************edge**********************/
 38 bool sign[N],vis[N];
 39 int n,m,a[N],tot,num[N],fa[N][20],dep[N];
 40 LL d[N];
 41 void dfs(int x){
 42     a[++tot]=x;
 43     num[x]=tot;
 44     F(i,1,17)
 45         if (dep[x]>=(1<<i)) fa[x][i]=fa[fa[x][i-1]][i-1];
 46         else break;
 47     for(int i=head[x];i;i=next[i])
 48         if (to[i]!=fa[x][0]){
 49             fa[to[i]][0]=x;
 50             dep[to[i]]=dep[x]+1;
 51             d[to[i]]=d[x]+len[i];
 52             dfs(to[i]);
 53         }
 54 }
 55 int LCA(int x,int y){
 56     if (dep[x]<dep[y]) swap(x,y);
 57     int t=dep[x]-dep[y];
 58     F(i,0,17) if (t&(1<<i)) x=fa[x][i];
 59     D(i,17,0) if (fa[x][i]!=fa[y][i])
 60         x=fa[x][i],y=fa[y][i];
 61     if (x==y) return x;
 62     return fa[x][0];
 63 }
 64 LL dis(int a,int b){
 65     return d[a]+d[b]-2*d[LCA(a,b)];
 66 }
 67 set<int>s;
 68 typedef set<int>::iterator SI;
 69 LL ans=0;
 70 void work(){
 71     dfs(1);
 72     int x;
 73     SI pre,suc,it;
 74     F(i,1,m){
 75         x=getint();
 76         sign[x]^=1;
 77         if (sign[x]){
 78             suc=pre=it=s.insert(num[x]).first;
 79             if (pre==s.begin()) pre=s.end(); pre--;
 80             suc++; if (suc==s.end()) suc=s.begin();
 81             ans-=dis(a[*suc],a[*pre]);
 82             ans+=dis(a[*suc],a[*it])+dis(a[*it],a[*pre]);
 83         }else{
 84             suc=pre=it=s.find(num[x]);
 85             if (pre==s.begin()) pre=s.end(); pre--;
 86             suc++; if (suc==s.end()) suc=s.begin();
 87             ans-=dis(a[*suc],a[*it])+dis(a[*it],a[*pre]);
 88             ans+=dis(a[*suc],a[*pre]);
 89             s.erase(it);
 90         }
 91         printf("%lld\n",ans);
 92     }
 93 }
 94 int main(){
 95 #ifndef ONLINE_JUDGE
 96     freopen("B.in","r",stdin);
 97 //  freopen("output.txt","w",stdout);
 98 #endif
 99     n=getint(); m=getint();
100     int x,y,z,mx=0;
101     F(i,2,n){
102         x=getint(); y=getint(); z=getint();
103         add(x,y,z);
104     }
105     work();
106     return 0;
107 }

3991: [Sdoi2015]寻宝游戏

Time Limit: 40 Sec  Memory Limit: 128 MB
Submit: 125  Solved: 74
[Submit][Status][Discuss]

Description

小B最近正在玩一个寻宝游戏,这个游戏的地图中有N个村庄和N-1条道路,并且任何两个村庄之间有且仅有一条路径可达。游戏开始时,玩家可以任意选择一个村庄,瞬间转移到这个村庄,然后可以任意在地图的道路上行走,若走到某个村庄中有宝物,则视为找到该村庄内的宝物,直到找到所有宝物并返回到最初转移到的村庄为止。小B希望评测一下这个游戏的难度,因此他需要知道玩家找到所有宝物需要行走的最短路程。但是这个游戏中宝物经常变化,有时某个村庄中会突然出现宝物,有时某个村庄内的宝物会突然消失,因此小B需要不断地更新数据,但是小B太懒了,不愿意自己计算,因此他向你求助。为了简化问题,我们认为最开始时所有村庄内均没有宝物

Input

第一行,两个整数N、M,其中M为宝物的变动次数。

接下来的N-1行,每行三个整数x、y、z,表示村庄x、y之间有一条长度为z的道路。

接下来的M行,每行一个整数t,表示一个宝物变动的操作。若该操作前村庄t内没有宝物,则操作后村庄内有宝物;若该操作前村庄t内有宝物,则操作后村庄内没有宝物。

Output

M行,每行一个整数,其中第i行的整数表示第i次操作之后玩家找到所有宝物需要行走的最短路程。若只有一个村庄内有宝物,或者所有村庄内都没有宝物,则输出0。

Sample Input

4 5
1 2 30
2 3 50
2 4 60
2
3
4
2
1

Sample Output

0
100
220
220
280

HINT

1<=N<=100000

1<=M<=100000

对于全部的数据,1<=z<=10^9

Source

Round 1 感谢yts1999上传

[Submit][Status][Discuss]

时间: 2024-10-13 00:03:58

【BZOJ】【3991】【SDOI2015】寻宝游戏的相关文章

bzoj 3991: [SDOI2015]寻宝游戏

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

BZOJ 3991 Sdoi2015 寻宝游戏 树链的并

题目大意:给定一棵树,多次将某个点设为关键点或取消关键点,求虚树中边长总和的二倍 Orz wyfcyx 首先我们考虑树链的并(每个点到根节点的链的并集)怎么求 将虚树中的所有点按照DFS序排序,将每个点的深度统计入答案,将相邻两个点之间的LCA的深度从答案中扣除,就是所有点到根的链的并集的长度 但是我们要求的是虚树中的边长总和,因此我们还要减掉所有点LCA的深度 现在要求动态维护,因此我们用set维护一下虚树的DFS序即可 各种开小数组忘开long long忘改lld我这是怎么了-- #incl

【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条道路,并且任何两个村庄之间有且仅有一条路径可达.游戏开始时,玩家可以任意选择一个村庄,瞬间转移到这个村庄,然后可以任意在地图的道路上行走,若走到某个村庄中有宝物,则视为找到该村庄内的宝物,直

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

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

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)\)个时刻中,每个时刻会发生以下三种类型的事件之一: 地图的某个点上出现了异象石(已经出现的不会再次出现); 地图某个点上的异象石被摧毁(不会摧毁没有异象石的点); 向玩家询问

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

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

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希望评测一下这个游戏的难度,因此他需要知道玩家找到所有宝物需要行走的最短路程.但是这个游戏中宝物经常变化,有时某个村庄中会突然

「一本通 4.4 例 3」异象石 与 [SDOI2015]寻宝游戏

这两个题差不多先说异象石把 主要是找到本题规律,将所加入的点按dfs序排序,记录为a[1],a[2]..a[n]则当前的答案为每个点与前一个点的距离(第一个点则与最后一点) 当然要动态维护答案,每加入一个点就+与前驱的距离+与后驱的距离-前驱与后驱的距离(删点的话ans减去这个值就好 不过异象石最后的答案要/2: 至于维护的话用set就好 1 #include<bits/stdc++.h> 2 #define ll long long 3 using namespace std; 4 cons