2025.5.1
P10722 [GESP202406 六级] 二叉树
题目描述
小杨有⼀棵包含 $n$ 个节点的二叉树,且根节点的编号为 $1$。这棵二叉树任意⼀个节点要么是白色,要么是黑色。之后小杨会对这棵二叉树进行 $q$ 次操作,每次小杨会选择⼀个节点,将以这个节点为根的子树内所有节点的颜色反转,即黑色变成白色,白色变成黑色。
小杨想知道 $q$ 次操作全部完成之后每个节点的颜色。
输入格式
第⼀行一个正整数 $n$,表示二叉树的节点数量。
第二行 $(n-1)$ 个正整数,第 $i$($1\le i\le n-1$)个数表示编号为 $(i+1)$ 的节点的父亲节点编号,数据保证是⼀棵二叉树。
第三行一个长度为 $n$ 的 $\texttt{01}$ 串,从左到右第 $i$($1\le i\le n$)位如果为 $\texttt{0}$,表示编号为 $i$ 的节点颜色为白色,否则为黑色。
第四行⼀个正整数 $q$,表示操作次数。
接下来 $q$ 行每行⼀个正整数 $a_i$($1\le a_i\le n$),表示第 $i$ 次操作选择的节点编号。
输出格式
输出一行一个长度为 $n$ 的 $\texttt{01}$ 串,表示 $q$ 次操作全部完成之后每个节点的颜色。从左到右第 $i$($1\le i\le n$) 位如果为 $\texttt{0}$,表示编号为 $i$ 的节点颜色为白色,否则为黑色。
输入输出样例 #1
输入 #1
6
3 1 1 3 4
100101
3
1
3
2
输出 #1
010000
说明/提示
样例解释
第一次操作后,节点颜色为:$\texttt{011010}$
第二次操作后,节点颜色为:$\texttt{000000}$
第三次操作后,节点颜色为:$\texttt{010000}$
数据范围
子任务编号 | 得分 | $n$ | $q$ | 特殊条件 |
---|---|---|---|---|
$1$ | $20$ | $\le 10^5$ | $\le 10^5$ | 对于所有 $i\ge 2$,节点 $i$ 的父亲节点编号为 $i-1$ |
$2$ | $40$ | $\le 1000$ | $\le 1000$ | |
$3$ | $40$ | $\le 10^5$ | $\le 10^5$ |
对于全部数据,保证有 $n,q\le 10^5$。
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int n;
int a[N],b[N];
int to[N],ne[N],h[N],idx=0;
void add(int u,int v){
to[++idx]=v;
ne[idx]=h[u];
h[u]=idx;
}
void dfs(int u,int cnt){
// cout<<a[u]<<endl;
a[u]=a[u]^cnt^b[u];
// cout<<a[u]<<endl;
for(int i=h[u];~i;i=ne[i]){
int v=to[i];
dfs(v,cnt^b[u]);
}
}
int main(){
cin>>n;
memset(h,-1,sizeof h);
for(int i=2;i<=n;i++){
int x;
cin>>x;
add(x,i);
}
string s;
cin>>s;
for(int i=0;s[i];i++){
if(s[i]=='0') a[i+1]=0;
else a[i+1]=1;
}
// for(int i=1;i<=n;i++) cout<<a[i]<<' ';
// cout<<endl;
int q;
cin>>q;
while(q--){
int x;
cin>>x;
b[x]^=1;
}
dfs(1,0);
for(int i=1;i<=n;i++)
cout<<a[i];
return 0;
}
P2052 [NOI2011] 道路修建
题目描述
在 W 星球上有 $n$ 个国家。为了各自国家的经济发展,他们决定在各个国家之间建设双向道路使得国家之间连通。但是每个国家的国王都很吝啬,他们只愿意修建恰好 $n - 1$ 条双向道路。
每条道路的修建都要付出一定的费用,这个费用等于道路长度乘以道路两端 的国家个数之差的绝对值。例如,在下图中,虚线所示道路两端分别有 $2$ 个、$4$ 个国家,如果该道路长度为 $1$,则费用为 $1×|2 - 4|=2$。图中圆圈里的数字表示国家的编号。
由于国家的数量十分庞大,道路的建造方案有很多种,同时每种方案的修建费用难以用人工计算,国王们决定找人设计一个软件,对于给定的建造方案,计算出所需要的费用。请你帮助国王们设计一个这样的软件。
输入格式
输入的第一行包含一个整数 $n$,表示 W 星球上的国家的数量,国家从 $1$ 到 $n$ 编号。
接下来 $n–1$ 行描述道路建设情况,其中第 $i$ 行包含三个整数 $a_i,b_i$ 和 $c_i$,表示第 $i$ 条双向道路修建在 $a_i$ 与 $b_i$ 两个国家之间,长度为 $c_i$。
输出格式
输出一个整数,表示修建所有道路所需要的总费用。
输入输出样例 #1
输入 #1
6
1 2 1
1 3 1
1 4 2
6 3 1
5 2 1
输出 #1
20
说明/提示
对于 $100%$ 的数据,$1\leq a_i, b_i\leq n$,$0\leq c_i\leq10^6$,$2\leq n\leq 10^6$。
测试点编号 | $n=$ |
---|---|
$1$ | $2$ |
$2$ | $10$ |
$3$ | $100$ |
$4$ | $200$ |
$5$ | $500$ |
$6$ | $600$ |
$7$ | $800$ |
$8$ | $1000$ |
$9$ | $10^4$ |
$10$ | $2\times 10^4$ |
$11$ | $5\times 10^4$ |
$12$ | $6\times 10^4$ |
$13$ | $8\times 10^4$ |
$14$ | $10^5$ |
$15$ | $6\times 10^5$ |
$16$ | $7\times 10^5$ |
$17$ | $8\times 10^5$ |
$18$ | $9\times 10^5$ |
$19,20$ | $10^6$ |
#include<bits/stdc++.h>
using namespace std;
const int N=2e6+10;
int n;
int to[N],ne[N],h[N],w[N],idx=0;
void add(int a,int b,int c){
to[++idx]=b;
ne[idx]=h[a];
h[a]=idx;
w[idx]=c;
}
int siz[N];
int ans=0;
void dfs(int u,int fa){
siz[u]=1;
for(int i=h[u];~i;i=ne[i]){
int v=to[i];
if(v!=fa){
dfs(v,u);
siz[u]+=siz[v];
ans+=abs(n-siz[v]*2)*w[i];
}
}
}
int main(){
cin>>n;
memset(h,-1,sizeof h);
memset(siz,0,sizeof siz);
for(int i=1;i<n;i++){
int a,b,c;
cin>>a>>b>>c;
add(a,b,c);
add(b,a,c);
}
dfs(1,0);
// for(int i=1;i<=n;i++) cout<<siz[i]<<' ';
cout<<ans<<endl;
return 0;
}
P1661 扩散
题目描述
一个点每过一个单位时间就会向四个方向扩散一个距离,如图。
两个点 $a$ 、 $b$ 连通,记作 $e(a,b)$,当且仅当 $a,b$ 的扩散区域有公共部分。连通块的定义是块内的任意两个点 $u,v$ 都必定存在路径 $e(u,a_0),e(a_0,a_1),\cdots,e(a_k,v)$。给定平面上的 $n$ 个点,问最早什么时刻它们形成一个连通块。
输入格式
第一行一个数 $n$,以下 $n$ 行,每行一个点坐标。
输出格式
一个数,表示最早的时刻所有点形成连通块。
输入输出样例 #1
输入 #1
2
0 0
5 5
输出 #1
5
说明/提示
数据范围及约定
对于 $20%$ 的数据,满足 $1 \le N \le 5;1 \le X_i,Y_i \le 50$。
对于 $100%$ 的数据,满足 $1 \le N \le 50$,$1 \le X_i,Y_i \le 10^9$。
#include<bits/stdc++.h>
#define int long long
#define x first
#define y second
using namespace std;
pair<int,int> p[100];
struct edge{
int u,v,w;
};
vector<edge> e;
bool cmp(edge a,edge b){
return a.w<b.w;
}
int f[100];
int find(int x){
if(f[x]!=x) f[x]=find(f[x]);
return f[x];
}
signed main(){
int n;
cin>>n;
for(int i=1;i<=n;i++)
cin>>p[i].x>>p[i].y;
for(int i=1;i<=n;i++) f[i]=i;
for(int i=1;i<=n;i++){
for(int j=i+1;j<=n;j++){
int dis=abs(p[i].x-p[j].x)+abs(p[i].y-p[j].y);
e.push_back({i,j,dis});
}
}
sort(e.begin(),e.end(),cmp);
int m=e.size();
int max_dis=0;
for(int i=0;i<m;i++){
int u=e[i].u,v=e[i].v;
int fu=find(u);
int fv=find(v);
if(fu!=fv){
f[fu]=fv;
max_dis=e[i].w;
}
}
cout<<(1+max_dis)/2<<endl;
return 0;
}
P1738 洛谷的文件夹
题目描述
kkksc03 是个非凡的空想家!在短时间内他设想了大量网页,然后总是交给可怜的 lzn 去实现。
洛谷的网页端,有很多文件夹,文件夹还套着文件夹。
例如:$\verb!/luogu/application/controller!$ 表示根目录下有一个名称为 $\verb!luogu!$ 的文件夹,这个文件夹下有一个名称 $\verb!application!$ 的文件夹,其中还有名为 $\verb!controller!$ 的文件夹。
每个路径的第 $1$ 个字符总是 $\verb!/!$,且没有两个连续的 $\verb!/!$,最后的字符不是 $\verb!/!$。所有名称仅包含数字和小写字母。
目前根目录是空的。kkksc03 想好了很多应该有的文件夹路径名。问题是,需要是使这些文件夹都存在,需要新建几个文件夹呢?
输入格式
输入文件第 $1$ 行为一个正整数 $N$。
接下来 $N$ 行,每行为一个描述路径的字符串,长度均不超过 $100$。
输出格式
输出应包含 $N$ 行,每行 $1$ 个正整数,第 $i$ 行输出若要使第 $1$ 个路径到第 $i$ 个路径存在,最少需要新建多少个文件夹。
输入输出样例 #1
输入 #1
2
/luogu/application/controller
/luogu/application/view
输出 #1
3
4
输入输出样例 #2
输入 #2
3
/chicken
/chicken/egg
/chicken
输出 #2
1
2
2
输入输出样例 #3
输入 #3
4
/a
/a/b
/a/c
/b/b
输出 #3
1
2
3
5
说明/提示
数据范围及约定
- 对于 $20%$ 数据,有 $N \le 20$;
- 对于 $50%$ 数据,有 $N \le 200$;
- 另有 $30%$ 数据,有对于所有路径最多存在两个 $\verb!/!$(包含第 $1$ 个字符);
- 对于所有数据,$N \le 1000$。
#include<bits/stdc++.h>
using namespace std;
int n;
int main(){
cin>>n;
set<string> st;
for(int i=1;i<=n;i++){
string s;
cin>>s;
string dir="";
for(int j=0;s[j];j++){
if(s[j]=='/') st.insert(dir);
dir+=s[j];
}
st.insert(dir);
cout<<(int)st.size()-1<<endl;
}
return 0;
}
#include<bits/stdc++.h>
using namespace std;
int n;
int main(){
cin>>n;
set<string> st;
for(int i=1;i<=n;i++){
string s;
cin>>s;
string dir="";
for(int j=1;s[j];j++){
if(s[j]=='/') st.insert(dir);
else dir+=s[j];
}
if(dir!="") st.insert(dir);
cout<<(int)st.size()<<endl;
}
return 0;
}
上述代码55/100原因在于/a/a和/aa混淆