Lovers【HDU-6562 2018CCPC吉林】【线段树】

题目链接


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吉林赛区(重现赛)- 感谢北华大学


  相当不错的一道题,比赛的时候,最后一个半小时没有敲出来(当时有了初步的想法,当然是错的),下来的时候补题,我太弱了,补了一整天,最终在晚上的时候给补完了。

  一开始看到这道题的时候,不理解什么是"d si d"(比赛的时候要是也像我现在这样拆开来,而不是链接在一起就好了),就是把原来的"si"这个数的左右,排上各一个"d"。

  那么,这里的单点时候相当于是怎样更新的呢?

  d * 100 + si * 10 + d;

是这样的,对吧。

然后呢,假如不是单个点呢,我们更新从l~r的点呢?是不是可以看成:

d * [ 10^(len(xl) + 1) + …… + 10^(len(xr) + 1) ] + 10 * [ xl + …… + xr ] + d * (r - l + 1);

那么,再简化一下,我们是不是可以推成这样:

d * 10 * [ 10^len(xl) + …… + 10^len(xr)  ] + 10 * [ xl + …… + xr ] + d * (r - l + 1);

  这时候,我们可以认为是更新到该区间(之后,我们会讲,如果是要pushdown()的时候的处理方式),那么我们不难发现,[ xl + …… + xr ]也就是上一次的状态,也就是之前没更新时候的区间和,所以这个是我们要维护的对吧;接下去,我们是不是还要维护一个 [ 10^len(xl) + …… + 10^len(xr)  ] 因为这个也不是很好处理,尤其是一个区间的时候,因为,我们要拿它去" * d * 10 "的说。所以,总结一下,我们维护sum1[ ]为 [ 10^len(xl) + …… + 10^len(xr)  ] ,再维护sum2[ ]为区间和( [ xl + …… + xr ] )。

  那么,如果我们现在要更新某个区间的时候,那么就是d * 10 * sum1[ ] + 10 * sum2[ ] + d * (r - l + 1)。

  这样是没错,但是呢,我们要是遇到了,我们查询的是它的一个子区间的话,这时候怎么办呢QAQ?好难处理的吧,(其实不难,我也不过是Debug了好几个小时罢了(雾)

  我们需要pushdown()的,这里又该怎样去推呢?我们这时候举例" d2 d1 x d1 d2 "是不是就是相当于把d2覆盖上来。那么我们是不是可以把头看成" 10 * d2 + d1 ",把尾看成" d1 * 10 + d2 ",中间部分是" x "但是这时候的" x "是x * 100了。

  放进线段树里,我们来看,我们是不是可以维护一个头,再维护一个尾,但是这样怎么确定x * "100"的这个"100"是多少呢,操作两次的时候是" * 100",三次的时候是" * 1000",那么以此类推,是不是可以维护一个操作的次数,然后我们这个操作的次数刚好也是可以反过来维护top的,所以我们维护头为lazytop[ ]、维护尾为lazyed[ ]、维护操作次数为lazylen[ ]。那么,我们先更新完区间和(因为区间和是用原来的sum1的),然后我们更新sum1,这时候需要注意的是sum1[ ] * ( 10^( lazylen[ ] * 2 ) )因为,前面top乘以的sum1是由两部分组成的,每次都会" *100 "所以,是两倍的。剩下的更新就不是很复杂了,可以自己试着推一下,反正前面那些我一开始云里雾里的弄了好久才理清楚了,可能是最近太头疼了吧……

对了,附上一组测试样例,一开始我过了题目的样例交了WA了之后找到的。

1
4 3
wrap 1 2 1
wrap 1 2 1
q 1 2
ans:2222
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const ll mod = 1e9 + 7;
const int maxN = 1e5 + 7;
int N, M;
ll ben_ten[maxN<<1];   //10^(i) % mod
ll sum1[maxN<<2], sum2[maxN<<2], lazytop[maxN<<2], lazyed[maxN<<2], lazylen[maxN<<2];
inline void pre_did()
{
    ben_ten[0] = 1;
    for(int i=1; i<200005; i++) ben_ten[i] = ben_ten[i-1] * 10 % mod;
}
inline void build(int rt, int l, int r)
{
    lazytop[rt] = lazyed[rt] = sum2[rt] = 0;
    lazylen[rt] = 0;
    sum1[rt] = r - l + 1;
    if(l == r) return;
    int mid = HalF;
    build(Lson); build(Rson);
    sum1[rt] = sum1[lsn] + sum1[rsn];
}
inline void pushdown(int rt, int l, int r)
{
    if(lazylen[rt])
    {
        int mid = HalF;
        sum2[lsn] = ( lazytop[rt] * sum1[lsn] % mod * ben_ten[lazylen[rt]] % mod + sum2[lsn] * ben_ten[lazylen[rt]] % mod + lazyed[rt] * (mid - l + 1) ) % mod;
        sum2[rsn] = ( lazytop[rt] * sum1[rsn] % mod * ben_ten[lazylen[rt]] % mod + sum2[rsn] * ben_ten[lazylen[rt]] % mod + lazyed[rt] * (r - mid) ) % mod;
        sum1[lsn] = sum1[lsn] * ben_ten[lazylen[rt]<<1] % mod;
        sum1[rsn] = sum1[rsn] * ben_ten[lazylen[rt]<<1] % mod;
        lazytop[lsn] = ( lazytop[lsn] + lazytop[rt] * ben_ten[lazylen[lsn]] ) % mod;
        lazytop[rsn] = ( lazytop[rsn] + lazytop[rt] * ben_ten[lazylen[rsn]] ) % mod;
        lazyed[lsn] = ( lazyed[lsn] * ben_ten[lazylen[rt]] + lazyed[rt] ) % mod;
        lazyed[rsn] = ( lazyed[rsn] * ben_ten[lazylen[rt]] + lazyed[rt] ) % mod;
        lazylen[lsn] = lazylen[lsn] + lazylen[rt];
        lazylen[rsn] = lazylen[rsn] + lazylen[rt];
        lazylen[rt] = lazytop[rt] = lazyed[rt] = 0;
    }
}
inline void update(int rt, int l, int r, int ql, int qr, int d)
{
    if(ql <= l && qr >= r)
    {
        sum2[rt] = ( sum1[rt] * d * 10 % mod + sum2[rt] * 10 % mod + d * (r - l + 1) ) % mod;
        sum1[rt] = sum1[rt] * 100 % mod;
        lazytop[rt] = ( lazytop[rt] + d * ben_ten[lazylen[rt]] % mod ) % mod;
        lazyed[rt] = ( lazyed[rt] * 10 + d ) % mod;
        lazylen[rt] ++;
        return;
    }
    pushdown(myself);
    int mid = HalF;
    if(qr <= mid) update(QL, d);
    else if(ql > mid) update(QR, d);
    else { update(QL, d); update(QR, d); }
    sum2[rt] = ( sum2[lsn] + sum2[rsn] ) % mod;
    sum1[rt] = ( sum1[lsn] + sum1[rsn] ) % mod;
}
inline ll query(int rt, int l, int r, int ql, int qr)
{
    if(ql <= l && qr >= r) return sum2[rt];
    int mid = HalF;
    pushdown(myself);
    if(qr <= mid) return query(QL);
    else if(ql > mid) return query(QR);
    else return ( query(QL) + query(QR) ) % mod;
}
char op[20];
int main()
{
    pre_did();
    int T; scanf("%d", &T);
    for(int Cas=1; Cas<=T; Cas++)
    {
        scanf("%d%d", &N, &M);
        build(1, 1, N);
        printf("Case %d:\n", Cas);
        int l, r, d;
        while(M--)
        {
            scanf("%s", op);
            scanf("%d%d", &l, &r);
            if(op[0] == 'w')
            {
                scanf("%d", &d);
                update(1, 1, N, l, r, d);
            }
            else printf("%lld\n", query(1, 1, N, l, r));
        }
    }
    return 0;
}
/*
1
4 3
wrap 1 2 1
wrap 1 2 1
q 1 2
ans:2222
 */

 

这题真的很不错,后来我又写了第二遍,思路清晰多了。

又多了组有用的数据:

1
3 3
w 1 3 0
w 1 3 1
q 1 1
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define efs 1e-6
#define INF 0x3f3f3f3f
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
#define MAX_3(a, b, c) max(max(a, b), c)
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const int maxN = 1e5 + 7;
const ll mod = 1e9 + 7;
int N, Q;
ll ten[maxN<<1];
inline void pre_did()
{
    ten[0] = 1LL;
    for(int i=1; i<200005; i++) ten[i] = ten[i-1] * (ll)10 % mod;
}
ll sum1[maxN<<2], sum2[maxN<<2], lazylen[maxN<<2], lazytop[maxN<<2], lazyed[maxN<<2];
inline void build(int rt, int l, int r)
{
    sum1[rt] = r - l + 1;
    sum2[rt] = lazylen[rt] = lazytop[rt] = lazyed[rt] = 0;
    if(l == r) return;
    int mid = HalF;
    build(Lson); build(Rson);
}
inline void pushdown(int rt, int l, int r)
{
    if(lazylen[rt])
    {
        int mid = HalF;
        sum2[lsn] = ( lazytop[rt] * ten[lazylen[rt]] % mod * sum1[lsn] % mod + ten[lazylen[rt]] * sum2[lsn] % mod + lazyed[rt] * (mid - l + 1) ) % mod;
        sum2[rsn] = ( lazytop[rt] * ten[lazylen[rt]] % mod * sum1[rsn] % mod + ten[lazylen[rt]] * sum2[rsn] % mod + lazyed[rt] * (r - mid) ) % mod;
        sum1[lsn] = sum1[lsn] * ten[lazylen[rt]<<1] % mod;
        sum1[rsn] = sum1[rsn] * ten[lazylen[rt]<<1] % mod;
        lazytop[lsn] = ( lazytop[lsn] + lazytop[rt] * ten[lazylen[lsn]] ) % mod;
        lazytop[rsn] = ( lazytop[rsn] + lazytop[rt] * ten[lazylen[rsn]] ) % mod;
        lazyed[lsn] = ( lazyed[lsn] * ten[lazylen[rt]] + lazyed[rt] ) % mod;
        lazyed[rsn] = ( lazyed[rsn] * ten[lazylen[rt]] + lazyed[rt] ) % mod;
        lazylen[lsn] += lazylen[rt]; lazylen[rsn] += lazylen[rt];
        lazylen[rt] = lazytop[rt] = lazyed[rt] = 0;
    }
}
inline void pushup(int rt) { sum1[rt] = ( sum1[lsn] + sum1[rsn] ) % mod; sum2[rt] = ( sum2[lsn] + sum2[rsn] ) % mod; }
inline void update(int rt, int l, int r, int ql, int qr, ll d)
{
    if(ql <= l && qr >= r)
    {
        sum2[rt] = ( d * 10 * sum1[rt] % mod + 10 * sum2[rt] + d * (r - l + 1) ) % mod;
        sum1[rt] = sum1[rt] * 100 % mod;
        lazytop[rt] = ( lazytop[rt] + d * ten[lazylen[rt]] ) % mod;
        lazyed[rt] = ( lazyed[rt] * 10 + d ) % mod;
        lazylen[rt]++;
        return;
    }
    pushdown(myself);
    int mid = HalF;
    if(qr <= mid) update(QL, d);
    else if(ql > mid) update(QR, d);
    else { update(QL, d); update(QR, d); }
    pushup(rt);
}
inline ll query(int rt, int l, int r, int ql, int qr)
{
    if(ql <= l && qr >= r) return sum2[rt];
    pushdown(myself);
    int mid = HalF;
    if(qr <= mid) return query(QL);
    else if(ql > mid) return query(QR);
    else return ( query(QL) + query(QR) ) % mod;
}
char op[20];
int main()
{
    pre_did();
    int T; scanf("%d", &T);
    for(int Cas = 1; Cas <= T; Cas++)
    {
        scanf("%d%d", &N, &Q);
        build(1, 1, N);
        int l, r; ll d;
        printf("Case %d:\n", Cas);
        while(Q--)
        {
            scanf("%s", op);
            scanf("%d%d", &l, &r);
            if(op[0] == 'w')
            {
                scanf("%lld", &d);
                update(1, 1, N, l, r, d);
            }
            else printf("%lld\n", query(1, 1, N, l, r));
        }
    }
    return 0;
}
/*
1
3 3
w 1 3 0
w 1 3 1
q 1 1
 */

 

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Wuliwuliii

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值