Codeforces Round #179 (Div. 2) C Greg and Array

C. Greg and Array
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

Greg has an array a = a1, a2, ..., an and m operations. Each operation looks as: liridi(1 ≤ li ≤ ri ≤ n). To apply operation i to the array means to increase all array elements with numbers li, li + 1, ..., ri by value di.

Greg wrote down k queries on a piece of paper. Each query has the following form: xiyi(1 ≤ xi ≤ yi ≤ m). That means that one should apply operations with numbers xi, xi + 1, ..., yi to the array.

Now Greg is wondering, what the array a will be after all the queries are executed. Help Greg.

Input

The first line contains integers nmk (1 ≤ n, m, k ≤ 105). The second line contains n integers: a1, a2, ..., an (0 ≤ ai ≤ 105) — the initial array.

Next m lines contain operations, the operation number i is written as three integers: liridi(1 ≤ li ≤ ri ≤ n)(0 ≤ di ≤ 105).

Next k lines contain the queries, the query number i is written as two integers: xiyi(1 ≤ xi ≤ yi ≤ m).

The numbers in the lines are separated by single spaces.

Output

On a single line print n integers a1, a2, ..., an — the array after executing all the queries. Separate the printed numbers by spaces.

Please, do not use the %lld specifier to read or write 64-bit integers in C++. It is preferred to use the cincout streams of the %I64dspecifier.

Sample test(s)
input
3 3 3
1 2 3
1 2 1
1 3 2
2 3 4
1 2
1 3
2 3
output
9 18 17
input
1 1 1
1
1 1 1
1 1
output
2
input
4 3 6
1 2 3 4
1 2 1
2 3 2
3 4 4
1 2
1 3
2 3
1 2
1 3
2 3
output
5 18 31 20

 

思路:这个题数据量很大。我用的方法是构造两个线段树来处理

首先要知道线段树的一个比较基本的模型,就是线段树成段的更新(一段+C或-C)

只要知道这个基本模型,题目可以分解为两不,第一步,利用x,y来构造线段树,判断每个操作出现了多少次

然后再把数组a[n]构造为一颗线段树,并且成段更新的时候,由于第一颗线段树已经可以知道当前这个操作执行了多少次,所以可以直接把di*c作为一个增加的量,来成段更新,这个di就是原来的增量,ci是通过第一颗线段树查找(i,i)这个区间出现的次数

最后把每一个ai都查找一次,就可以得到答案了。

#include<stdio.h>
#include<string.h>

struct node
{
	__int64 l;
	__int64 r;
	__int64 d;
	__int64 val;
};
struct control
{
	__int64 l;
	__int64 r;
	__int64 d;
};
node tree1[400000];
node tree2[400000];
control con[100005];
__int64 num[100005],sum1,sum2;
__int64 cnm[100005];

void build_tree1(__int64 l,__int64 r,__int64 root)
{
	tree1[root].l=l;
	tree1[root].r=r;
	if(l==r)
	{
		tree1[root].val=0;
		tree1[root].d=0;
		return;
	}
	__int64 mid=(l+r)>>1;
	build_tree1(l,mid,root*2);
	build_tree1(mid+1,r,root*2+1);
	tree1[root].val=tree1[root*2].val+tree1[root*2+1].val;
	tree1[root].d=0;
}


void build_tree2(__int64 l,__int64 r,__int64 root)
{
	tree2[root].l=l;
	tree2[root].r=r;
	if(l==r)
	{
		tree2[root].val=num[l];
		tree2[root].d=0;
		return;
	}
	__int64 mid=(l+r)>>1;
	build_tree2(l,mid,root*2);
	build_tree2(mid+1,r,root*2+1);
	tree2[root].val=tree2[root*2].val+tree2[root*2+1].val;
	tree2[root].d=0;
}

void findsum1(__int64 l,__int64 r,__int64 root)
{
	if(tree1[root].l==l&&tree1[root].r==r)
	{
		sum1=sum1+tree1[root].val;
		return;
	}
	sum1=sum1+(r-l+1)*tree1[root].d;
	__int64 mid=(tree1[root].l+tree1[root].r)>>1;
	if(mid>=r)
		findsum1(l,r,root*2);
	else if(mid<l)
		findsum1(l,r,root*2+1);
	else
	{
		findsum1(l,mid,root*2);
		findsum1(mid+1,r,root*2+1);
	}
}

void findsum2(__int64 l,__int64 r,__int64 root)
{
	if(tree2[root].l==l&&tree2[root].r==r)
	{
		sum2=sum2+tree2[root].val;
		return;
	}
	sum2=sum2+(r-l+1)*tree2[root].d;
	__int64 mid=(tree2[root].l+tree2[root].r)>>1;
	if(mid>=r)
		findsum2(l,r,root*2);
	else if(mid<l)
		findsum2(l,r,root*2+1);
	else
	{
		findsum2(l,mid,root*2);
		findsum2(mid+1,r,root*2+1);
	}
}

void update1(__int64 l,__int64 r,__int64 c,__int64 root)
{
	tree1[root].val=tree1[root].val+((r-l+1)*c);
	if(tree1[root].l==l&&tree1[root].r==r)
	{
		tree1[root].d=tree1[root].d+c;
		return;
	}
	__int64 mid=(tree1[root].l+tree1[root].r)>>1;
	if(mid>=r)
		update1(l,r,c,root*2);
	else if(mid<l)
		update1(l,r,c,root*2+1);
	else
	{
		update1(l,mid,c,root*2);
		update1(mid+1,r,c,root*2+1);
	}
}

void update2(__int64 l,__int64 r,__int64 c,__int64 root)
{
	tree2[root].val=tree2[root].val+((r-l+1)*c);
	if(tree2[root].l==l&&tree2[root].r==r)
	{
		tree2[root].d=tree2[root].d+c;
		return;
	}
	__int64 mid=(tree2[root].l+tree2[root].r)>>1;
	if(mid>=r)
		update2(l,r,c,root*2);
	else if(mid<l)
		update2(l,r,c,root*2+1);
	else
	{
		update2(l,mid,c,root*2);
		update2(mid+1,r,c,root*2+1);
	}
}

int main()
{
	__int64 i,n,a,b,c,m,k;
	while(scanf("%I64d%I64d%I64d",&n,&m,&k)!=EOF)
	{
		for(i=1;i<=n;i++)
			scanf("%I64d",&num[i]);
		build_tree1(1,m,1);
		for(i=1;i<=m;i++)
		{
			scanf("%I64d%I64d%I64d",&a,&b,&c);
			con[i].l=a;
			con[i].r=b;
			con[i].d=c;
		}
		for(i=1;i<=k;i++)
		{
			scanf("%I64d%I64d",&a,&b);
			update1(a,b,1,1);
		}
		for(i=1;i<=m;i++)
		{
			sum1=0;
			findsum1(i,i,1);
			cnm[i]=sum1;
		}
		build_tree2(1,n,1);
		for(i=1;i<=m;i++)
			update2(con[i].l,con[i].r,con[i].d*cnm[i],1);
		for(i=1;i<n;i++)
		{
			sum2=0;
			findsum2(i,i,1);
			printf("%I64d ",sum2);
		}
		sum2=0;
		findsum2(n,n,1);
		printf("%I64d\n",sum2);
	}
	return 0;
}


 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值