[硬核线段树] 2018CCPC吉林I.lovers

Lovers

Time Limit: 25000/15000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 351    Accepted Submission(s): 104


 

Problem Description

The Fool comes to a cross-road, filled with energy, confidence and purpose, knowing exactly where he wants to go and what he wants to do. But he comes to a dead stop. A flowering tree marks the path he wants to take, the one he’s been planning on taking. But standing before a fruit tree marking the other path is a woman. The Fool has met and had relationships with women before, some far more beautiful and alluring. But she is different. Seeing her, he feels as though he’s just been shot in the heart with cupid’s arrow.

There are n empty strings:

s1, s2, . . . , sn.


You are required to perform two kinds of operations:

  • wrap l r d: change si to dsid for all l ≤ i ≤ r, where d is a digit character.
  • query l r: query ∑i=lr value(si) (mod 109 + 7), where value(s) is the number that string s represents.


     
  • Note that the value of an empty string is 0.

 

 

Input

The first line contains one integer T, which denote the number of cases.
For each case, the first line contains two integer n and m where n is the number of strings and m is the number of operations.
Each line of the following m lines contains an operation with format

wrap l r d


or

query l r

.

 

 

Output

For each case, you should output "Case i:"in a line, where i is the case number starting from 1.
Then for each query operation in that case, output a line that contains a single integer that representing the answer for that query operation.

 

 

Sample Input

 

2

3 2

wrap 1 3 1

query 1 2

4 4

wrap 1 3 0

wrap 2 4 3

query 1 4

query 2 3

 

 

Sample Output

 

Case 1:

22

Case 2:

6039

6006

Hint

1 ≤ T ≤ 5, 1 ≤ n, m ≤ 1e5, 1 ≤ l ≤ r ≤ n.

 

 

Source

2018CCPC吉林赛区(重现赛)- 感谢北华大学

 

/******* 

题解:对于一个数字x若执行第一个操作则 

则若对于一个区间sum(l,r)执行第一个操作则  

设 则便可以用线段树去维护这两个东西便可,这里只考虑了d是一位数的情况,但是在线段树下传标记的过程中可能一个区间多次执行第一个操作,那么wrap的d便不是一位数,而且左右两边的d是镜像的,我们便要用两个lazy标记,lazy1维护左边加的数,lazy2维护右边加的数,同时可以用lazylen表示这两个lazy的,然后好好考虑一下如何维护sum和sumlen即可
--------------------- 
作者:Sher杨 
来源:CSDN 
原文:https://blog.csdn.net/sudu6666/article/details/89887056 
版权声明:本文为博主原创文章,转载请附上博文链接!

*******/

#include <bits/stdc++.h>
#define ll long long
#define db double
using namespace std;

const ll mod = 1e9 + 7;
const int mn = 1e5 + 10;

ll sum[4 * mn], len[4 * mn], lazy1[4 * mn], lazy2[4 * mn], lazylen[4 * mn];

void build(int id, int l, int r)
{
	sum[id] = 0;
	len[id] = lazylen[id] = 1;
	lazy1[id] = lazy2[id] = 0;
	if (l == r)
		return;
	int mid = (l + r) >> 1;
	build(2 * id, l, mid);
	build(2 * id + 1, mid + 1, r);
	sum[id] = (sum[2 * id] + sum[2 * id + 1]) % mod;
	len[id] = (len[2 * id] + len[2 * id + 1]) % mod;
}
void pushdown(int id, int l, int r)
{
	if (lazylen[id] == 1) return;
	
	lazy1[2 * id] = (lazy1[id] * lazylen[2 * id] % mod + lazy1[2 * id]) % mod;
	lazy1[2 * id + 1] = (lazy1[id] * lazylen[2 * id + 1] % mod + lazy1[2 * id + 1]) % mod;
	lazy2[2 * id] = (lazy2[2 * id] * lazylen[id] % mod + lazy2[id]) % mod;
	lazy2[2 * id + 1] = (lazy2[2 * id + 1] * lazylen[id] % mod + lazy2[id]) % mod;
	
	int mid = (l + r) >> 1;
	sum[2 * id] = (lazy1[id] * len[2 * id] % mod * lazylen[id] % mod + sum[2 * id] * lazylen[id] % mod + lazy2[id] * (mid - l + 1)) % mod;
	sum[2 * id + 1] = (lazy1[id] * len[2 * id + 1] % mod * lazylen[id] % mod + sum[2 * id + 1] * lazylen[id] % mod + lazy2[id] * (r - mid)) % mod;
	len[2 * id] = len[2 * id] * lazylen[id] % mod * lazylen[id] % mod;
	len[2 * id + 1] = len[2 * id + 1] * lazylen[id] % mod * lazylen[id] % mod;
	
	lazylen[2 * id] = (lazylen[2 * id] * lazylen[id]) % mod;
	lazylen[2 * id + 1] = (lazylen[2 * id + 1] * lazylen[id]) % mod;
	
	lazy1[id] = 0, lazy2[id] = 0, lazylen[id] = 1;
}
void update(int L, int R, ll k, int id, int l, int r)
{
	if (L == l && r == R)
	{
		sum[id] = (k * len[id] % mod * 10 % mod + sum[id] * 10 % mod + k * (r - l + 1) % mod) % mod;
		len[id] = len[id] * 100 % mod;
		
		lazy1[id] = (k * lazylen[id] % mod + lazy1[id]) % mod;
		lazy2[id] = (lazy2[id] * 10 + k) % mod;
		lazylen[id] = lazylen[id] * 10 % mod;
		
		return;
	}
	pushdown(id, l, r);
	int mid = (l + r) >> 1;
	if (R <= mid) update(L, R, k, 2 * id, l, mid);
	else if (mid + 1 <= L) update(L, R, k, 2 * id + 1, mid + 1, r);
	else 
	{
		update(L, mid, k, 2 * id, l, mid);
		update(mid + 1, R, k, 2 * id + 1, mid + 1, r);
	}
	sum[id] = (sum[2 * id] + sum[2 * id + 1]) % mod;
	len[id] = (len[2 * id] + len[2 * id + 1]) % mod;
}
ll query(int L, int R, int id, int l, int r)
{
	if (L == l && r == R)
		return sum[id];
	pushdown(id, l, r);
	int mid = (l + r) >> 1;
	if (R <= mid) return query(L, R, 2 * id, l, mid);
	else if (mid + 1 <= L) return query(L, R, 2 * id + 1, mid + 1, r);
	else return (query(L, mid, 2 * id, l, mid) + query(mid + 1, R, 2 * id + 1, mid + 1, r)) % mod;
}

int main()
{
	int T;
	scanf("%d", &T);
	for (int cas = 1; cas <= T; cas++)
	{
		printf("Case %d:\n", cas);

		int n, m;
		scanf("%d %d", &n, &m);

		build(1, 1, n);
		
		while (m--)
		{
			char ch[10]; scanf("%s", ch);
			int l, r;
			ll k;
			if (ch[0] == 'w')
			{
				scanf("%d %d %lld", &l, &r, &k);
				update(l, r, k, 1, 1, n);
			}
			else if (ch[0] == 'q')
			{
				scanf("%d %d", &l, &r);
				printf("%lld\n", query(l, r, 1, 1, n));
			}
		}
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值