#A. Peaks
- 传统题 1000ms 256MiB
Description
有n个点,m条无向边,给定这n个点的权值和这m条边连结的点.
不保证图的连通性
我们称这样的点v为Peak点
即它的权值严格大于它的周边点
所谓周边点就是与v通过一条边直接相连的点
请统计Peak点的个数
Format
Input
第一行给出N,M
第二行给出N个点的权值
接下来M行,每行两个数字,代表边的情况
N,M<=1e5
Output
如题
Samples
输入数据 1
4 3
1 2 3 4
1 3
2 3
2 4
输出数据 1
2
输入数据 2
10 9
877034223 133899794 476916052 912077132 335047010 225936408 355083132 818106283 721973481 718651389
7 9
7 4
5 6
5 9
2 5
6 1
1 9
2 8
5 6
输出数据 2
5
树的遍历
递归
#include<bits/stdc++.h>
#define fof(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
vector<int>d[100005];
int n,m,pt[100005],x,y,ans;
bool ck(int p)
{
fof(i,0,int(d[p].size()-1))
if(pt[p]<=pt[d[p][i]])
return false;
return true;
}
int main()
{
scanf("%d %d",&n,&m);
fof(i,1,n)
scanf("%d",&pt[i]);
fof(i,1,m)
{
scanf("%d %d",&x,&y);
d[x].push_back(y);
d[y].push_back(x);
}
fof(i,1,n)
if(ck(i)==true)
ans++;
printf("%d",ans);
return 0;
}
#B. Ki
- 传统题 1000ms 256MiB
Description
给出一棵以1为根的树,有N个点,每个点上有一个计数器,初始0
接下来Q次操作,每次操作将p_i的子树中所有点的计数器增加x_i,输出最后每个点的计数器值
Format
Input
第一行给出N,Q
接下来N-1行描述这个树
再接下来Q行,每行给出Pi,Xi
2<=N<=2e5
1<=Q<=2e5
xi<=1e4
Output
如题
Samples
输入数据 1
4 3
1 2
2 3
2 4
2 10
1 100
3 1
输出数据 1
100 110 111 110
1.0版本
#include<bits/stdc++.h>
using namespace std;
int n,q,dep[200005],x,p;
vector<int>d[200005];
void fac(int ddp,int f)
{
dep[ddp]+=x;
for(int i=0;i<=int(d[ddp].size()-1);i++)
if(d[ddp][i]!f)
fac(d[ddp][i],ddp);
return ;
}
int main()
{
scanf("%d %d",&n,&q);
memset(dep,63,sizeof(p));
dep[1]=1;
for(int i=1;i<=n-1;i++)
{
scanf("%d %d",&x,&p);
d[x].push_back(p);
d[p].push_back(x);
}
memset(dep,0,sizeof(dep));
for(int i=1;i<=q;i++)
{
scanf("%d %d",&p,&x);
fac(p,0);
}
for(int i=1;i<=n;i++)
printf("%d ",dep[i]);
return 0;
}
时间复杂度N*Q
考虑优化:因为加数规则和递归遍历树一样,都是从根到叶子点,所以每个点的总值为加在这个点上的+加在这个点的父亲节点上的。
2.0版本
#include<bits/stdc++.h>
using namespace std;
int n,q,x,y,p,ans[200005];
vector<int>d[200005];
void ad(int pl,int sum,int f)
{
ans[pl]+=sum;
for(int i=0;i<=int(d[pl].size()-1);i++)
if (d[pl][i]!=f)
ad(d[pl][i],ans[pl],pl);
return ;
}
int main()
{
scanf("%d %d",&n,&q);
for(int i=1;i<=n-1;i++)
{
scanf("%d %d",&x,&y);
d[x].push_back(y);
d[y].push_back(x);
}
for(int i=1;i<=q;i++)
{
scanf("%d %d",&p,&x);
ans[p]+=x;
}
ad(1,0,0);
for(int i=1;i<=n;i++)
printf("%d ",ans[i]);
return 0;
}
#C. Cow Marathon
传统题 1000ms 256MiB
Description
给你一棵树,求树上距离最远的两个点
Format
Input
第一行给数字N,M,代表共有N个点,M条边
接下来M行,每行格式为
a b c d:点a与点b之间有一条长度为c的边,d是一个字母,不用管它
Output
如题
Samples
输入数据 1
7 6
1 6 13 E
6 3 9 E
3 5 7 S
4 1 3 N
2 4 20 W
4 7 2 S
输出数据 1
52
Hint
The longest marathon runs from farm 2 via roads 4, 1, 6 and 3 to farm 5 and is of length 20+3+13+9+7=52.
#include<bits/stdc++.h>
using namespace std;
int n,m,x,y,z,ans=INT_MIN,mx1[1000000],mx2[1000000];
char xxx;
struct inf
{
int u,len;
};
vector<inf>d[1000000];
void trc(int pl,int f)
{
for(int i=0;i<=int(d[pl].size()-1);i++)
if(d[pl][i].u!=f)
{
trc(d[pl][i].u,pl);
int k=mx1[d[pl][i].u]+d[pl][i].len;
if(k>mx1[pl])
swap(k,mx1[pl]);
if(k>mx2[pl])
swap(k,mx2[pl]);
}
ans=max(ans,mx1[pl]+mx2[pl]);
return ;
}
int main()
{
scanf("%d %d",&n,&m);
for(int i=1;i<=m;i++)
{
scanf("%d %d %d %s",&x,&y,&z,&xxx);
d[x].push_back({y,z});
d[y].push_back({x,z});
}
trc(1,0);
printf("%d",ans);
return 0;
}
#D. 树上的旅行
- 传统题 1000ms 256MiB
Description
给出一棵有N个结点的树,给出Q个询问,求结点xj过结点K到节点yj的最短距离
Format
Input
第一行一个数n
接下来共有n-1行,三个数u,v,len表示u和v之间存在一条边长为len
再给你Q,K。代表有Q个询问,K就是那个必经过
接下来Q行,每行两个数字xj,yj
N,Q<=1e6
len<=1e9
Output
如题
Samples
输入数据 1
5
1 2 1
1 3 1
2 4 1
3 5 1
3 1
2 4
2 3
4 5
输出数据 1
3
2
4
和C差不多
#include<bits/stdc++.h>
using namespace std;
int n,x,y,z,q,k;
long long ans[1000005];
struct inf
{
long long u,len;
};
vector<inf>d[1000005];
void trc(int pl,int f)
{
for(int i=0;i<=int(d[pl].size()-1);i++)
if(d[pl][i].u!=f)
{
ans[d[pl][i].u]=ans[pl]+d[pl][i].len;
trc(d[pl][i].u,pl);
}
return ;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n-1;i++)
{
scanf("%d %d %d",&x,&y,&z);
d[x].push_back({y,z});
d[y].push_back({x,z});
}
scanf("%d %d",&q,&k);
trc(k,0);
for(int i=1;i<=q;i++)
{
scanf("%d %d",&x,&y);
printf("%lld\n",ans[x]+ans[y]);
}
return 0;
}
#E. 时态同步
- 传统题 1000ms 256MiB
D escription
A国有N个城市,其中国王住在编号为S的城市中。
整个国家通过N-1条边连接起来,嗯,就是一棵树的结构了
国王有若干个儿子住在叶子城市中。
为了保护这些王子,国王在城市的连通线上安排了一些士兵。
现在为了体现他的均衡,国王决定再多派一些士兵,使得从S城出发到任一个叶子点 其路径上的士兵数量是一样的。
请问国王最少要派多少个士兵。
Format
Input
第一行给出N
第二行给出S
接下来N-1行,每行三个数字a,b,c代表a城到b城的边上有c名士兵
N ≤ 500000
c≤ 1000000
Output
如题
Samples
输入数据 1
3
1
1 2 1
1 3 3
输出数据 1
2
#include<bits/stdc++.h>
using namespace std;
int n,s,x,y;
long long ans,z,sum[5000005];
struct inf
{
long long u,len;
};
vector<inf>d[500005];
void trc(int pl,int f)
{
for(int i=0;i<=int(d[pl].size()-1);i++)
if(d[pl][i].u!=f)
{
trc(d[pl][i].u,pl);
sum[pl]=max(sum[pl],sum[d[pl][i].u]+d[pl][i].len);
}
for(int i=0;i<=int(d[pl].size()-1);i++)
if(d[pl][i].u!=f)
ans+=sum[pl]-d[pl][i].len-sum[d[pl][i].u];
return ;
}
int main()
{
scanf("%d%d",&n,&s);
for(int i=1;i<=n-1;i++)
{
scanf("%d%d%d",&x,&y,&z);
d[x].push_back({y,z});
d[y].push_back({x,z});
}
trc(s,0);
printf("%lld",ans);
return 0;
}
#F. 危险计算机
- 传统题 1000ms 128MiB
说明
N台计算机由N-1条网线连接,形成了一个树形网络。这些计算机经常会被黑客攻击,如果这个树形网络中的某一台计算机遭到攻击而导致系统瘫痪,那么与这台计算机连接的所有网线就无法进行数据传输,整个网络就会被分成若干个小的树形网络,每个小网络由一台或多台计算机组成。如果一台计算机被攻击后,形成的每个小网络中包含的计算机数都不超过N/2,那么这台计算机就会成为重点攻击对象,称作“危险计算机”。给定一个树形网络,请你找出网络中所有的“危险计算机”。
输入格式
第一行是一个整数N(1≤N ≤20000),表示计算机的台数,计算机被编号为1..N。下面N-1行,每行包括两个整数X, Y,表示X和Y这两台计算机之间由一条网线连接。
输出格式
包括若干行,每行为一台危险计算机的编号,按升序排列。如果没有危险计算机,就输出一行,只包含一个字符串“NONE”(不包括引号)
样例
输入数据 1
10
1 2
2 3
3 4
4 5
6 7
7 8
8 9
9 10
3 8
输出数据 1
3
8
#include<bits/stdc++.h>
using namespace std;
int n,x,y,v[20005],ans[20005],ff;
vector<int>d[20005];
void trc(int p,int f)
{
v[p]=1;
for(int i=0;i<=int(d[p].size()-1);i++)
if(d[p][i]!=f)
{
trc(d[p][i],p);
v[p]+=v[d[p][i]];
ans[p]=max(ans[p],v[d[p][i]]);
}
ans[p]=max(ans[p],n-v[p]);
return ;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n-1;i++)
{
scanf("%d%d",&x,&y);
d[x].push_back(y);
d[y].push_back(x);
}
trc(1,0);
for(int i=1;i<=n;i++)
if(ans[i]<=n/2)
{
printf("%d\n",i);
ff=33;
}
if(ff!=33)
printf("NONE");
return 0;
}