长春理工大学第十四届程序设计竞赛(重现赛)-K-Master of Graph

链接:https://ac.nowcoder.com/acm/contest/912/K
来源:牛客网
 

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld

题目描述

"好像有点感觉哦"--小x( Master of Graph)


每当图论大师小x看到图,他都会说一句"好像有点感觉哦",他以为自己有掌控图的能力,能把某些特定编号的点的权值修改成自己想要的值,所以每次修改后他都会自信回头(不管了),

但是他的队友(咋胡佬)发现小x并没有把那些特定编号的点的权值修改成他想要的值,由于小x给力的操作(给力哦铁汁),假设点原来的权值为x,修改后会变成f(x)(f(x)是统计十进制数字x每一位的和),

咋胡佬发现了这一规律后,自信满满地来到小x面前询问他某些特定编号的点的权值和,

您作为小x的死忠粉iXiang也发现了这一规律,自然不希望自己的idol(偶像)受到质疑,因此您决定帮助小x一一回答咋胡佬的问题
 

输入描述:

第一行一个数字n,m(1 <= n,m <= 100000,以空格分隔),表示图的点数和边数。

第二行n个数字ai(0 <= ai <= 1000000000000,以空格分隔),表示编号为i的点的权值为ai。

接下来m行,每行两个数字(1 <= u,v <= n),代表编号u的点和编号为v的点之间的无向边

接下来一行,一个数字q(1 <= q <= 100000),表示有q个事件。

接下来q行,每行三个数字"x l r",(1 <= l <= r <= n)。

若x为1,代表小x对编号为l到r所有点的权值进行修改,您无需输出,但修改对后面的事件有影响

若x为0,代表咋胡佬对小x的询问,您需要输出编号l到r所有点的权值和

输出描述:

对于每个操作0,输出编号区间[l,r]的和。

示例1

输入

复制

10 9
3841 45109 42780 10844 63078 15424 7341 8629 56972 10886
1 2
1 3
2 4
2 5
7 4
5 8
6 3
6 9
10 9
6
1 2 10
0 10 10
0 9 10
0 2 3
1 3 3
0 1 10

输出

复制

23
52
40
4012

地址:https://ac.nowcoder.com/acm/contest/912/K

思路:区间线段树

对于f()函数可以分析发现每个a[i]最多执行3次就不会改变了,因此将此作为线段树的标记。每次更新若有标记则可以跳过,否则直接更新到叶子节点,可以判断更新标记即可

Code:

#include<iostream>
#include<cstdio>
using namespace std;
typedef long long LL;

const int MAX_N=1e5+5;
struct tree{
	int l,r;
	int lazy;
	LL x;
	int mid(){
		return (l+r)>>1;
	}
};
int n,m,Q;
LL a[MAX_N];
tree Tree[MAX_N<<2];

LL F(LL x){
	LL res=0;
	while(x){
		res+=x%10;
		x/=10;
	}
	return res;
}

void PushUp(int rt);
void PushDown(int rt);
void Build(int l,int r,int rt);
void Update(int l,int r,LL x,int rt);
LL Query(int l,int r,int rt);
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;++i)
		scanf("%lld",&a[i]);
	Build(1,n,1);
	int u,v;
	while(m--){
		scanf("%d%d",&u,&v);
	}
	scanf("%d",&Q);
	int tx,l,r;
	while(Q--){
		scanf("%d%d%d",&tx,&l,&r);
		if(tx)	Update(l,r,1,1);
		else	printf("%lld\n",Query(l,r,1));
	}
	
	return 0;
}

void PushUp(int rt)
{
	Tree[rt].x=Tree[rt<<1].x+Tree[(rt<<1)|1].x;
}

void Build(int l,int r,int rt)
{
	Tree[rt].l=l;	Tree[rt].r=r;
	if(l==r){
		Tree[rt].x=a[l];	return;
	}
	int h=(l+r)>>1;
	Build(l,h,rt<<1);
	Build(h+1,r,(rt<<1)|1);
	PushUp(rt);
}

void Update(int l,int r,LL x,int rt)
{
	if(Tree[rt].lazy)	return;
	if(Tree[rt].l==Tree[rt].r){
		Tree[rt].x=F(Tree[rt].x);
		if(Tree[rt].x<10)	Tree[rt].lazy=1;
		return;
	}
	int H=Tree[rt].mid();
	if(H>=l)	Update(l,r,x,rt<<1);
	if(H<r)	Update(l,r,x,(rt<<1)|1);
	Tree[rt].lazy=(Tree[rt<<1].lazy&&Tree[(rt<<1)|1].lazy);
	PushUp(rt);
}

LL Query(int l,int r,int rt)
{
	if(l<=Tree[rt].l&&r>=Tree[rt].r)	return Tree[rt].x;
	LL res=0;
	int H=Tree[rt].mid();
	if(H>=l)	res+=Query(l,r,rt<<1);
	if(H<r)	res+=Query(l,r,(rt<<1)|1);
	return res;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值