游客观光
时间限制:1s 内存限制:128M
题目描述
H国有个城市,它们之间用
条道路连接了起来,所有的城市之间刚好只有一条路径。由于H国有着举世闻名的自然风光,因此吸引了世界各地的游客前来观光。
H国有山有水,个城市的风景各有侧重点,有些城市崇山峻岭,有些城市波光粼粼,每个城市的风景属于山和水的其中一种。
作为H国的旅游局长,小猴收到了位游客的参观计划,第
位游客会从城市
到城市
的路径进行参观(
可能等于
)。
每位游客对自然风光有自己的喜好,有些人只喜欢看山,有些人只喜欢看水。如果游客在参观途中能看到自己喜欢的景色,他们就会感到高兴,否则就会不高兴。
请你帮小猴求出每位游客在拜访H国后会不会高兴。
【输入格式】
输入的第一行包含两个整数 和
。
第二行是一个长为 的字符串。如果第
个城市的景点是山,则字符串中第
个字符为 'M',如果第
个城市的景点是水则为 'W'。
接下来 行,每行包含两个不同的整数
和
(
),表示城市
与
之间有一条道路。
接下来 行,每行包含整数
,
,以及一个字符
。
和
表示游客
参观时路径的端点,
是 'M' 或 'W' 之一,表示第 ii 个朋友喜欢看山或是看水。
【输出格式】
输出一个长为 的二进制字符串。如果第
位游客会感到高兴,则字符串的第
个字符为 '1',否则为 '0'。
【输入输出样例#1】
输入#1
5 5
MMWMW
1 2
2 3
2 4
1 5
1 4 M
1 4 W
1 3 W
1 3 M
5 5 M
输出#1
10110
【说明提示】
【样例解释】
在这里,从城市1 到城市4 的路径包括城市 1、2 和 4。所有这些城市的景点都是山,所以第一位游客会感到满意,而第二位游客不会。
【数据范围】
对于的数据,
,
。
一看题目,哎呀,好像很简单,一看数据范围,放弃了
我们很快便能想出一种的算法,思路是遇上一个游客,就bfs一下,再判断一下就行了。但这样很麻烦,甚至会错掉。
那么,怎么优化呢?其实还有种方法,用的是dfs,是找到一个点的周边的属性相同的点的连通块。就是找到风景相同的、中间不会遇上风景不同的城市。这样记录下来,会很方便
但,这种方法在极端数据,不,是大数据面前就会崩溃,只能得42分
此时,主角登场了
它,就是大名鼎鼎的
并查集
并查集,具有速度快、效率高、占用空间较小等优点,可以快速合并两个集合,图论的Kruskal、连通图,以及LCA,均有涉及
板子大家都会(要用上路径压缩、子树大小判断等),怎么个合并办法呢?
当两城有路且风景相同时,要合并
代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
int f[100007],size[100007],n,m,a,b;
char c;
char x[100007];
void init(int m){for(int i=1;i<=m;i++) f[i]=i,size[i]=1;}
int find(int x){return (x==f[x])?x:find(f[x]);}//仔细观察,看似短小精悍的、天衣无缝的代码里有一处巨大的漏洞,你找到了吗?
void merge(int a,int b){
if(find(a)==find(b))
return;
if(size[a]>size[b])
f[find(a)]=find(b),size[b]+=size[a];
else
f[find(b)]=find(a),size[a]+=size[b];
}
signed main(){
scanf("%lld%lld",&n,&m);
init(n);
scanf("%s",x+1);
for(int i=1;i<n;i++){
scanf("%lld%lld",&a,&b);
if(x[a]==x[b])
merge(a,b);
}
while(m--){
scanf("\n%lld %lld %c",&a,&b,&c);
if(find(a)!=find(b))
putchar('1');
else if(x[a]==c)
putchar('1');
else
putchar('0');
}
return 0;
}
然而只有50分
还有什么可做的吗?
有!
问题在find函数里,递归时栈的调用会很慢,还容易爆栈,可以改为非递归,AC(就是如此神奇,看来下次少用递归了)
#include<bits/stdc++.h>
using namespace std;
#define int long long
int f[100007],size[100007],n,m,a,b;
char c;
char x[100007];
void init(int m){for(int i=1;i<=m;i++) f[i]=i,size[i]=1;}
int find(int x){
int ans,nx=x;
while(nx!=f[nx]){
nx=f[nx];
}
while(x!=f[x]){
int l=f[x];
f[x]=nx;
x=l;
}
return nx;
}
void merge(int a,int b){
if(find(a)==find(b))
return;
if(size[a]>size[b])
f[find(a)]=find(b),size[b]+=size[a];
else
f[find(b)]=find(a),size[a]+=size[b];
}
signed main(){
scanf("%lld%lld",&n,&m);
init(n);
scanf("%s",x+1);
for(int i=1;i<n;i++){
scanf("%lld%lld",&a,&b);
if(x[a]==x[b])
merge(a,b);
}
while(m--){
scanf("\n%lld %lld %c",&a,&b,&c);
if(find(a)!=find(b))
putchar('1');
else if(x[a]==c)
putchar('1');
else
putchar('0');
}
return 0;
}
小猴编程(8375039373182185)