2023.8.21&22

#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;
}

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值