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)

 //Huce #4 B
#include<set>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define rep(i,n) for(int i=0;i<n;++i)
#define F(i,j,n) for(int i=j;i<=n;++i)
#define D(i,j,n) for(int i=j;i>=n;--i)
using namespace std; int getint(){
int v=,sign=; char ch=getchar();
while(ch<''||ch>'') {if (ch=='-') sign=-; ch=getchar();}
while(ch>=''&&ch<='') {v=v*+ch-''; ch=getchar();}
return v*sign;
}
typedef long long LL;
const int N=,INF=~0u>>;
/*******************tamplate********************/
int head[N],to[N<<],next[N<<],len[N<<],cnt;
void add(int x,int y,int z){
to[++cnt]=y; next[cnt]=head[x]; len[cnt]=z; head[x]=cnt;
to[++cnt]=x; next[cnt]=head[y]; len[cnt]=z; head[y]=cnt;
}
/*********************edge**********************/
int n,m,du[N];
bool sign[N],vis[N]; namespace work1{
LL ans;
bool dfs(int x){
bool tmp=sign[x];
vis[x]=;
for(int i=head[x];i;i=next[i]) if(!vis[to[i]]){
if (dfs(to[i])){
ans+=len[i];
tmp=;
}
}
return tmp;
}
LL solve(){
ans=;
memset(vis,,sizeof vis);
F(i,,n) if (sign[i]){
dfs(i);
return ans;
}
}
void work1(){
int x;
F(i,,m){
x=getint(); sign[x]^=;
printf("%lld\n",solve()*);
}
}
}
namespace work2{
int a[N],tot,num[N];
LL sum[N];
void dfs(int x,int l){
vis[x]=;
a[++tot]=x;
sum[tot]=sum[tot-]+l;
num[x]=tot;
for(int i=head[x];i;i=next[i])
if (!vis[to[i]])
dfs(to[i],len[i]);
}
set<int>s;
set<int>::iterator it;
void work2(){
F(i,,n) if (du[i]==){
dfs(i,);
break;
}
// F(i,1,tot) printf("%d ",a[i]);puts("");
int x;
F(i,,m){
x=getint();
sign[x]^=;
if (sign[x]) s.insert(num[x]);
else{
it=s.find(num[x]);
s.erase(it);
}
it=s.end(); it--;
// printf("%d %d\n",*s.begin(),*s.rbegin());
printf("%lld\n",(sum[*s.rbegin()]-sum[*s.begin()])*);
}
}
}
namespace work3{
int fa[N],num[N],dis[N];
LL ans;
bool vis[N];
void dfs(int x){
vis[x]=;
for(int i=head[x];i;i=next[i])
if (!vis[to[i]]){
fa[to[i]]=x;
dis[to[i]]=len[i];
dfs(to[i]);
}
}
void update(int x,int v){
if (x==) return;
if (v==){
num[x]++;
if (num[x]==) ans+=dis[x];
}else{
num[x]--;
if (num[x]==) ans-=dis[x];
}
update(fa[x],v);
}
void work3(){
int x;
memset(vis,,sizeof vis);
dfs();
// F(i,1,n) printf("%d ",dis[i]); puts("");
F(i,,m){
x=getint(); sign[x]^=;
update(x,sign[x]?:-);
printf("%lld\n",ans*);
}
}
}
int main(){
#ifndef ONLINE_JUDGE
freopen("B.in","r",stdin);
// freopen("output.txt","w",stdout);
#endif
n=getint(); m=getint();
int x,y,z,mx=;
F(i,,n){
x=getint(); y=getint(); z=getint();
add(x,y,z);
du[x]++; du[y]++;
mx=max(mx,max(du[x],du[y]));
}
if (n<=) work1::work1();
else if (mx==) work2::work2();
else
work3::work3();
return ;
}

50分暴力

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

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

  QAQ我还是too young too naive

 /**************************************************************
Problem: 3991
User: Tunix
Language: C++
Result: Accepted
Time:7188 ms
Memory:19016 kb
****************************************************************/ //Huce #4 B
#include<set>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define rep(i,n) for(int i=0;i<n;++i)
#define F(i,j,n) for(int i=j;i<=n;++i)
#define D(i,j,n) for(int i=j;i>=n;--i)
using namespace std; int getint(){
int v=,sign=; char ch=getchar();
while(ch<''||ch>'') {if (ch=='-') sign=-; ch=getchar();}
while(ch>=''&&ch<='') {v=v*+ch-''; ch=getchar();}
return v*sign;
}
typedef long long LL;
const int N=,INF=~0u>>;
/*******************tamplate********************/
int head[N],to[N<<],next[N<<],len[N<<],cnt;
void add(int x,int y,int z){
to[++cnt]=y; next[cnt]=head[x]; len[cnt]=z; head[x]=cnt;
to[++cnt]=x; next[cnt]=head[y]; len[cnt]=z; head[y]=cnt;
}
/*********************edge**********************/
bool sign[N],vis[N];
int n,m,a[N],tot,num[N],fa[N][],dep[N];
LL d[N];
void dfs(int x){
a[++tot]=x;
num[x]=tot;
F(i,,)
if (dep[x]>=(<<i)) fa[x][i]=fa[fa[x][i-]][i-];
else break;
for(int i=head[x];i;i=next[i])
if (to[i]!=fa[x][]){
fa[to[i]][]=x;
dep[to[i]]=dep[x]+;
d[to[i]]=d[x]+len[i];
dfs(to[i]);
}
}
int LCA(int x,int y){
if (dep[x]<dep[y]) swap(x,y);
int t=dep[x]-dep[y];
F(i,,) if (t&(<<i)) x=fa[x][i];
D(i,,) if (fa[x][i]!=fa[y][i])
x=fa[x][i],y=fa[y][i];
if (x==y) return x;
return fa[x][];
}
LL dis(int a,int b){
return d[a]+d[b]-*d[LCA(a,b)];
}
set<int>s;
typedef set<int>::iterator SI;
LL ans=;
void work(){
dfs();
int x;
SI pre,suc,it;
F(i,,m){
x=getint();
sign[x]^=;
if (sign[x]){
suc=pre=it=s.insert(num[x]).first;
if (pre==s.begin()) pre=s.end(); pre--;
suc++; if (suc==s.end()) suc=s.begin();
ans-=dis(a[*suc],a[*pre]);
ans+=dis(a[*suc],a[*it])+dis(a[*it],a[*pre]);
}else{
suc=pre=it=s.find(num[x]);
if (pre==s.begin()) pre=s.end(); pre--;
suc++; if (suc==s.end()) suc=s.begin();
ans-=dis(a[*suc],a[*it])+dis(a[*it],a[*pre]);
ans+=dis(a[*suc],a[*pre]);
s.erase(it);
}
printf("%lld\n",ans);
}
}
int main(){
#ifndef ONLINE_JUDGE
freopen("B.in","r",stdin);
// freopen("output.txt","w",stdout);
#endif
n=getint(); m=getint();
int x,y,z,mx=;
F(i,,n){
x=getint(); y=getint(); z=getint();
add(x,y,z);
}
work();
return ;
}

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

[Submit][Status][Discuss]

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

  1. bzoj 3991: [SDOI2015]寻宝游戏 虚树 set

    目录 题目链接 题解 代码 题目链接 bzoj 3991: [SDOI2015]寻宝游戏 题解 发现每次答案就是把虚树上的路径*2 接在同一关键点上的点的dfs序是相邻的 那么用set动态维护dfs序 ...

  2. 树形结构的维护:BZOJ 3991: [SDOI2015]寻宝游戏

    Description 小B最近正在玩一个寻宝游戏,这个游戏的地图中有N个村庄和N-1条道路,并且任何两个村庄之间有且仅有一条路径可达.游戏开始时,玩家可以任意选择一个村庄,瞬间转移到这个村庄,然后可 ...

  3. bzoj 3991: [SDOI2015]寻宝游戏

    Description 小B最近正在玩一个寻宝游戏,这个游戏的地图中有N个村庄和N-1条道路,并且任何两个村庄之间有且仅有一条路径可达.游戏开始时,玩家可以任意选择一个村庄,瞬间转移到这个村庄,然后可 ...

  4. BZOJ 3991: [SDOI2015]寻宝游戏 树链的并+set

    Description 小B最近正在玩一个寻宝游戏,这个游戏的地图中有N个村庄和N-1条道路,并且任何两个村庄之间有且仅有一条路径可达.游戏开始时,玩家可以任意选择一个村庄,瞬间转移到这个村庄,然后可 ...

  5. [BZOJ 3991][SDOI2015]寻宝游戏(dfs序)

    题面 小B最近正在玩一个寻宝游戏,这个游戏的地图中有N个村庄和N-1条道路,并且任何两个村庄之间有且仅有一条路径可达.游戏开始时,玩家可以任意选择一个村庄,瞬间转移到这个村庄,然后可以任意在地图的道路 ...

  6. BZOJ 3991: [SDOI2015]寻宝游戏 [虚树 树链的并 set]

    传送门 题意: $n$个点的树,$m$次变动使得某个点有宝物或没宝物,询问每次变动后集齐所有宝物并返回原点的最小距离 转化成有根树,求树链的并... 两两树链求并就可以,但我们按照$dfs$序来两两求 ...

  7. BZOJ.3991.[SDOI2015]寻宝游戏(思路 set)

    题目链接 从哪个点出发最短路径都是一样的(最后都要回来). 脑补一下,最短路应该是按照DFS的顺序,依次访问.回溯遍历所有点,然后再回到起点. 即按DFS序排序后,Ans=dis(p1,p2)+dis ...

  8. 3991: [SDOI2015]寻宝游戏

    3991: [SDOI2015]寻宝游戏 https://www.lydsy.com/JudgeOnline/problem.php?id=3991 分析: 虚树+set. 要求树上许多点之间的路径的 ...

  9. 【BZOJ】3991: [SDOI2015]寻宝游戏

    题意 给一个\(n\)个点带边权的树.有\(m\)次操作,每一次操作一个点\(x\),如果\(x\)已经出现,则\(x\)消失.否则\(x\)出现.每一操作后,询问从某个点开始走,直到经过所有出现的点 ...

  10. 【BZOJ】3991: [SDOI2015]寻宝游戏 虚树+DFS序+set

    [题意]给定n个点的带边权树,对于树上存在的若干特殊点,要求任选一个点开始将所有特殊点走遍后返回.现在初始没有特殊点,m次操作每次增加或减少一个特殊点,求每次操作后的总代价.n,m<=10^5. ...

随机推荐

  1. Spark RDD的依赖解读

    在Spark中, RDD是有依赖关系的,这种依赖关系有两种类型 窄依赖(Narrow Dependency) 宽依赖(Wide Dependency) 以下图说明RDD的窄依赖和宽依赖 窄依赖 窄依赖 ...

  2. 安装pdo.so和pdo_mysql.so还有pcntl.so扩展到php中

    1.下载源码,解压tar -xzvf php-5.4.20.tar.gz cd  /usr/local/src/php-5.4.20/ext/pdo /usr/local/php/bin/phpize ...

  3. LotusPhp中配置文件组件LtConfig详解

    LotusPhp中配置文件组件LtConfig是约定的一个重要组成部分,适用于多个场景,多数的LotusPhp组件如数据库,缓存,RBAC,表单验证等都需要用到配置组件,LtConfig配置组件也是L ...

  4. 种树 (codevs 1653) 题解

    [问题描述] 一条街的一边有几座房子.因为环保原因居民想要在路边种些树.路边的地区被分割成块,并被编号为1..n.每个块大小为一个单位尺寸并最多可种一棵树.每个居民想在门前种些树并指定了三个号码b,e ...

  5. Ghost命令使用方法

    我们知道,一般使用Ghost时,都是在DOS提示符后先键入"Ghost",然后再进入Ghost的图形界面操作:那么可不可以让Ghost也只通过命令行的方式工作呢?答案是肯定的,在键 ...

  6. mongodb 3.2存储目录结构说明

    [root@hadoop1 mongodb]# tree ./data ./data |-- WiredTiger | |-- WiredTiger.lock | |-- WiredTiger.tur ...

  7. Unity加入Android广告小结

    在Unity游戏加入广告大致有以下几种方式: 导入Android Jar包 导出游戏为Android项目(在Build时选中Google Android Project,这种方法可以参考将Unity3 ...

  8. Android--WebView显示Html,让其中的图片适应屏幕宽度

    //设置 防止图片太大超出屏幕 tv_web_danGe.getSettings().setLayoutAlgorithm(WebSettings.LayoutAlgorithm.SINGLE_COL ...

  9. Android操作系统11种传感器介绍

    我们依次看看这十一种传感器 1 加速度传感器 加速度传感器又叫G-sensor,返回x.y.z三轴的加速度数值. 该数值包含地心引力的影响,单位是m/s^2. 将手机平放在桌面上,x轴默认为0,y轴默 ...

  10. < java.util >-- Collection接口

    Collection:    |--List:有序(元素存入集合的顺序和取出的顺序一致),元素都有索引.元素可以重复.    |--Set:无序(存入和取出顺序有可能不一致),不可以存储重复元素.必须 ...