2018年9月23日提高组

A 农夫约的假期

在某国有一个叫农夫约的人,他养了很多羊,其中有两头名叫mm和hh,他们的歌声十分好听,被当地人称为“魔音”······
农夫约也有自己的假期呀!他要去海边度假,然而mm和hh不能离开他。没办法,他只好把他们两个带上。
到了海边,农夫约把他的羊放在一个(nn)的矩阵(有nn个方格)里。mm和hh十分好动,他们要走到m(m<=n*n)个地方,第i个地方的坐标为(x[i](行),y[i](列)),每到一个地方他们会高歌一曲,制造q[i]点魔音值,因为他们的魔音十分独特,他们的声音只能横着或竖着传播。每传播一格,魔音值会增加1。(传播的格子数取最小的)接下来农夫约要住酒店。为了方便照顾小羊们,他选的酒店的坐标要在矩阵内。但小羊们的魔音让他十分头疼。他想求出魔音值最小的地方。
他还要享受他的假期,所以他把这个任务交给你了,加油(_)。

  求中位数即可
#include <cstdio>
#include <algorithm>

using namespace std;

int n,m,z;
int x[100005],y[100005],q[100005];

int main(){
	scanf("%d%d%d",&n,&m,&z);
	for (int i=1;i<=m;i++)
		scanf("%d%d%d",&x[i],&y[i],&q[i]);
		
	sort(x+1,x+1+m);
	sort(y+1,y+1+m);
	int cx,cy;
	long long ans=0;
	cx=x[m/2];cy=y[m/2];
	if (m%2==1){
			cx=x[m/2+1];cy=y[m/2+1];
	}	
	for (int i=1;i<=m;i++)
		ans+=abs(x[i]-cx)*z+abs(y[i]-cy)*z+q[i];
	printf("%lld\n",ans);
	printf("%d %d",cx,cy);
}

B 小x游世界树

小x得到了一个(不可靠的)小道消息,传说中的神岛阿瓦隆在格陵兰海的某处,据说那里埋藏着亚瑟王的宝藏,这引起了小x的好奇,但当他想前往阿瓦隆时发现那里只有圣诞节时才能到达,然而现在已经春天了,不甘心的他将自己的目的地改成了世界树,他耗费了大量的时间,终于将自己传送到了世界树下。世界树是一棵非常巨大的树,它有着许许多多的枝条以及节点,每个节点上都有一个平台。好不容易来到传说中的世界树下,小x当然要爬上去看看风景。小x每经过一条边都会耗费体力值。然而世界树之主想给他弄(gáo)些(dǐan)麻(shì)烦(qíng),于是他在每条边上都设了一个魔法阵,当小x踏上那条边时会被传送回根节点,魔法阵只生效一次。这岂不是要累死小x?幸运的是,每个平台上都有无数个加速器,这些加速器可以让小x在当前节点所连的边上耗费的体力值减少,不同平台的加速器性能不一定相同,但同一个平台的加速器性能绝对相同。世界树之主给了小x一次“换根”的机会,他可以将世界树的任何一个节点变为根,但所有的边都不能改变。小x想问你,将根换为哪个节点能使小x爬到世界树上的每个节点耗费的体力值和最少。默认编号为1的点为初始根。

下面是一个修改中未完成的程序

#include <cstdio>
#include <cstring>

using namespace std;

int n,ans,st,cnt;
int a[700005];
int ls[700005],ne[700005],to[700005],d[700005];
int b[700005],f[700005],son[700005];

void dfs(int k){
	b[k]=1;
	int u=ls[k],bz=0,bbz=0;
	while (u){
		if (!b[to[u]]){
			int ccd=(son[k]-son[to[u]])*d[u^1]-son[to[u]]*d[u];
			f[to[u]]+=ccd+f[k];
			if (f[to[u]]<ans){ans=f[to[u]];st=to[u];}
			dfs(to[u]);
			
		}
		u=ne[u];
	}
}

void dfs1(int k){
	b[k]=1;
	son[k]=1;
	int u=ls[k];
	int sss=f[k];
	while (u){
		if (!b[to[u]]){
			f[to[u]]=f[k]+d[u];			
			dfs1(to[u]);
			son[k]+=son[to[u]];
			sss+=f[to[u]];
		}
		u=ne[u];
	}
	f[k]=sss;
}

int main(){
	scanf("%d",&n);
	for (int i=1;i<=n;i++)
		scanf("%d",&a[i]);
	cnt=1;
	for (int i=1;i<n;i++){
		int x,y,z;
		scanf("%d%d%d",&x,&y,&z);
		ne[++cnt]=ls[x];ls[x]=cnt;to[cnt]=y;d[cnt]=z-a[x];
		ne[++cnt]=ls[y];ls[y]=cnt;to[cnt]=x;d[cnt]=z-a[y];
	}
	memset(b,0,sizeof(b));
	memset(f,0,sizeof(f));
	dfs1(1);
	ans=f[1];st=1;
	
	memset(b,0,sizeof(b));
	dfs(1);
		
	printf("%d\n",st);
	printf("%d",ans);
}

C 观察

出题人给出一颗以1为根的树,一开始每个节点都是一颗棋子,一面白一面黑,白色的面朝上
接下来就q次操作,操作分两种
0操作 将一个颗棋子翻转
1操作 询问一颗棋子与所有面朝上为黑色的棋子lca最深的那个的编号
在这里插入图片描述

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值