博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【BZOJ】【3991】【SDOI2015】寻宝游戏
阅读量:5150 次
发布时间:2019-06-13

本文共 6710 字,大约阅读时间需要 22 分钟。

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
3 #include
4 #include
5 #include
6 #include
7 #include
8 #include
9 #define rep(i,n) for(int i=0;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
s; 74 set
::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_JUDGE134 freopen("B.in","r",stdin);135 // freopen("output.txt","w",stdout);136 #endif137 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
12 #include
13 #include
14 #include
15 #include
16 #include
17 #include
18 #define rep(i,n) for(int i=0;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<
s; 68 typedef set
::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 }
View Code

3991: [Sdoi2015]寻宝游戏

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

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

[ ][ ][ ]

转载于:https://www.cnblogs.com/Tunix/p/4442334.html

你可能感兴趣的文章
死磕 java集合之TreeMap源码分析(三)- 内含红黑树分析全过程
查看>>
《C#多线程编程实战》2.8 Barrier
查看>>
学习笔记42—Win7下安装Linux双系统
查看>>
树行DP小结
查看>>
静态库 动态库
查看>>
编程异常——假设你报createSQLQuery is not valid without active transaction,...
查看>>
YII 路由配置
查看>>
hdoj 1506&amp;&amp;1505(City Game) dp
查看>>
【微信公众平台开发】百度周边搜索接口php封装
查看>>
mac开启22port
查看>>
Solaris 10下使用Python3
查看>>
Android 从硬件到应用程序:一步一步爬上去 6 -- 我写的APP测试框架层硬件服务(终点)...
查看>>
android的EditText获取另一个焦点
查看>>
常见hash算法的原理
查看>>
ios新开发语言swift 新手教程
查看>>
Android应用中使用百度地图API定位自己的位置(二)
查看>>
有引用外部jar包时(J2SE)生成jar文件
查看>>
写接口请求类型为get或post的时,参数定义的几种方式,如何用注解(原创)--雷锋...
查看>>
什么是 开发环境、测试环境、生产环境、UAT环境、仿真环境
查看>>
科研需要兴趣和自信
查看>>