HDU6562 2018CCPC Jilin Station H lovers (good question for line segment tree)

Question:
Given a string set of length n, s1, s2,...sn, each string is an empty string at the beginning.
Now given m
operations, there are two operation options for each operation:
warp lrd It means that every number in the interval from l to r becomes dsid. For example, the original si=“33”, and then d=5, then si becomes “5335”.
query lr asks every string in this interval What is the sum of the numbers represented, the empty string is equivalent to 0 to calculate

For a number x, updating x is equivalent to: 10 * x + d + d * 10 len(x) , len(x) represents how many digits of the number x currently has,
so for an interval sum, the update operation is equivalent to: 10 * sum + d * (r-l+1) + d * ∑10 len(xi) .
So we need to maintain the line segment tree first . A tree array represents the sum of the current node and a len array represents the digit length of the number represented by the current node. , And then because of the need to complete the interval update requirements, the lazy array is also needed, but if only one array is not easy to maintain, the lazy is separated, a lazl represents the updated value of the left half, and a lazr represents the updated value of the right half , And then a lazlen represents the length of the lazy interval. The
query operation is nothing special.
Update operation:

		tree[rt] = (tree[rt]*10%MOD + val*(r-l+1)%MOD + 10*val*len[rt]%MOD)%MOD;
		len[rt] = len[rt]*100%MOD;
		lazr[rt] = (lazr[rt]*10%MOD + val)%MOD;
		lazl[rt] = (val*lazlen[rt]%MOD + lazl[rt])%MOD;
		lazlen[rt] = lazlen[rt]*10%MOD;//一侧就只加了一位

In the first summation tree, len[rt] must be multiplied by 10 to leave a position for the val on the left. The
right mark is multiplied by 10 plus val. The mark on the left needs to be multiplied by the length of the mark. Add the original mark, and the final mark length only needs to be multiplied by 10, because the length of one side section is recorded.

Then there is the operation
of pushing down the mark, which is also the most troublesome operation: tree (that is, the interval sum) is obtained in two parts, the right side is multiplied by lazlen plus the right mark of the parent node multiplied by the length of the current subinterval, and the left The side is the left mark of the parent node multiplied by lazlen and then multiplied by the digit length of the current child node.
The len array needs to be multiplied by the lazlen array of the parent node twice, because the left and right mark intervals maintained by lazlen, the length of the two together is the mark contribution of the total interval length.
The left tag array is the left tag array of the parent node multiplied by the current lazlen and the original left tag array is added. The
right tag array is the parent node's lazlen multiplied by the current right tag array plus the parent node's right tag array
lazlen Just multiply my lazlen of the parent node.
Don’t forget to clear all the marks after all these operations are done.

void pushdown(int rt,int tot)
{
    
    
	if(lazlen[rt] > 1){
    
    
		//子节点 第一部分 当前子节点乘以父节点lazy的长度 再加上父节点的有lazy即为子节点的右边答案
		//第二部分 父节点 的 做lazy值乘以父节点的lazy长度乘以子节点的长度 这两部分加起来 即是子节点更新完成的答案
		tree[rt<<1] = (tree[rt<<1]*lazlen[rt]%MOD + (tot-tot/2)*lazr[rt]%MOD + (lazl[rt]*lazlen[rt])%MOD*len[rt<<1]%MOD)%MOD;
		tree[rt<<1|1] = (tree[rt<<1|1]*lazlen[rt]%MOD + (tot/2)*lazr[rt]%MOD + (lazl[rt]*lazlen[rt])%MOD*len[rt<<1|1]%MOD)%MOD;

		len[rt<<1] = len[rt<<1]*lazlen[rt]%MOD*lazlen[rt]%MOD;//乘两次 才能把他们的贡献 都算上
		len[rt<<1|1] = len[rt<<1|1]*lazlen[rt]%MOD*lazlen[rt]%MOD;

		lazl[rt<<1] = (lazlen[rt<<1]*lazl[rt]%MOD + lazl[rt<<1])%MOD;
		lazl[rt<<1|1] = (lazlen[rt<<1|1]*lazl[rt]%MOD + lazl[rt<<1|1])%MOD;

		lazr[rt<<1] = (lazlen[rt]*lazr[rt<<1]%MOD + lazr[rt])%MOD;//空出 父节点 lazy个长度 来让右边的lazy更新上	
		lazr[rt<<1|1] = (lazlen[rt]*lazr[rt<<1|1]%MOD + lazr[rt])%MOD;

		lazlen[rt<<1] = (lazlen[rt<<1]*lazlen[rt])%MOD;//只是一边的长度 不需要 两边 都乘以这个长度
		lazlen[rt<<1|1] = (lazlen[rt<<1|1]*lazlen[rt])%MOD;

		lazr[rt] = lazl[rt] = 0;
		lazlen[rt] = 1;//别忘了消除标记的影响
	}
}

The rest are normal operations.
Code:

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
const int MAXN = 1e5+7;
const int MOD = 1e9+7;
char s[17];
ll tree[MAXN<<2],len[MAXN<<2],lazl[MAXN<<2],lazr[MAXN<<2],lazlen[MAXN<<2];

void build(int rt,int l,int r)
{
    
    
	tree[rt] = lazr[rt] = lazl[rt] = 0;
	lazlen[rt] = 1;
	if(l == r){
    
    
		len[rt] = 1;
		return ;
	}
	int mid = (l+r)>>1;
	build(rt<<1,l,mid);
	build(rt<<1|1,mid+1,r);
	len[rt] = (len[rt<<1] + len[rt<<1|1])%MOD;
}

void pushdown(int rt,int tot)
{
    
    
	if(lazlen[rt] > 1){
    
    
		//子节点 第一部分 当前子节点乘以父节点lazy的长度 再加上父节点的有lazy即为子节点的右边答案
		//第二部分 父节点 的 做lazy值乘以父节点的lazy长度乘以子节点的长度 这两部分加起来 即是子节点更新完成的答案
		tree[rt<<1] = (tree[rt<<1]*lazlen[rt]%MOD + (tot-tot/2)*lazr[rt]%MOD + (lazl[rt]*lazlen[rt])%MOD*len[rt<<1]%MOD)%MOD;
		tree[rt<<1|1] = (tree[rt<<1|1]*lazlen[rt]%MOD + (tot/2)*lazr[rt]%MOD + (lazl[rt]*lazlen[rt])%MOD*len[rt<<1|1]%MOD)%MOD;

		len[rt<<1] = len[rt<<1]*lazlen[rt]%MOD*lazlen[rt]%MOD;//乘两次 才能把他们的贡献 都算上
		len[rt<<1|1] = len[rt<<1|1]*lazlen[rt]%MOD*lazlen[rt]%MOD;

		lazl[rt<<1] = (lazlen[rt<<1]*lazl[rt]%MOD + lazl[rt<<1])%MOD;
		lazl[rt<<1|1] = (lazlen[rt<<1|1]*lazl[rt]%MOD + lazl[rt<<1|1])%MOD;

		lazr[rt<<1] = (lazlen[rt]*lazr[rt<<1]%MOD + lazr[rt])%MOD;//空出 父节点 lazy个长度 来让右边的lazy更新上	
		lazr[rt<<1|1] = (lazlen[rt]*lazr[rt<<1|1]%MOD + lazr[rt])%MOD;

		lazlen[rt<<1] = (lazlen[rt<<1]*lazlen[rt])%MOD;//只是一边的长度 不需要 两边 都乘以这个长度
		lazlen[rt<<1|1] = (lazlen[rt<<1|1]*lazlen[rt])%MOD;

		lazr[rt] = lazl[rt] = 0;
		lazlen[rt] = 1;//别忘了消除标记的影响
	}
}

void update(int rt,int l,int r,int L,int R,int val)
{
    
    
	if(l >= L && r <= R){
    
    
		tree[rt] = (tree[rt]*10%MOD + val*(r-l+1)%MOD + 10*val*len[rt]%MOD)%MOD;
		len[rt] = len[rt]*100%MOD;
		lazr[rt] = (lazr[rt]*10%MOD + val)%MOD;
		lazl[rt] = (val*lazlen[rt]%MOD + lazl[rt])%MOD;
		lazlen[rt] = lazlen[rt]*10%MOD;//一侧就只加了一位
		return ;
	}
	pushdown(rt,r-l+1);
	int mid = (l+r)>>1;
	if(L <= mid) update(rt<<1,l,mid,L,R,val);
	if(R > mid) update(rt<<1|1,mid+1,r,L,R,val);
	tree[rt] = (tree[rt<<1] + tree[rt<<1|1])%MOD;
	len[rt] = (len[rt<<1] + len[rt<<1|1])%MOD;
}

ll query(int rt,int l,int r,int ql,int qr)
{
    
    
	if(l >= ql && r <= qr){
    
    
		return tree[rt];
	}
	pushdown(rt,r-l+1);
	int mid = (l+r)>>1;
	ll ans = 0;
	if(ql <= mid) ans = (ans+ query(rt<<1,l,mid,ql,qr))%MOD;
	if(qr > mid) ans = (ans + query(rt<<1|1,mid+1,r,ql,qr))%MOD;
	return ans;
}

int main()
{
    
    
	int T,cas = 0;
	scanf("%d",&T);
	while(T--){
    
    
		int n,m;
		scanf("%d%d",&n,&m);
		build(1,1,n);
		printf("Case %d:\n",++cas);
		while(m--){
    
    
			int l,r,x;
			scanf("%s",s);
			if(s[0] == 'w'){
    
    
				scanf("%d%d%d",&l,&r,&x);
				update(1,1,n,l,r,x);
			}
			else if(s[0] == 'q'){
    
    
				scanf("%d%d",&l,&r);
				ll ans = query(1,1,n,l,r);
				printf("%lld\n",ans);
			}
		}
	}
	return 0;
}

Guess you like

Origin blog.csdn.net/weixin_45672411/article/details/108623635