zoukankan      html  css  js  c++  java
  • CCPC 2018 吉林 H "LOVERS" (线段树)

    ---恢复内容开始---

    传送门

    参考资料:

      [1]:https://blog.csdn.net/mmk27_word/article/details/89788448

    题目描述:
        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 ∑value(si)(mod 1e9+7) (for all l <= i <= r),where value(s) is the number that string s represents.
    
    Note that the value of an empty string is 0.
    
    输入
        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).
    
    输出
        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.
    题目描述
    样例输入:
    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
    
    样例输出
    Case 1:
    22
    Case 2:
    6039
    6006
    样例输入输出

    所有思路均来自参考资料,下面只是谈谈本蒟蒻的进一步理解:

      定义 f(s) = strlen(s);

      对串 s1 执行 swap 操作,可得到新串 ds1d,转换成数字就是 10*d*10f(s1)+s1*10+d;

      那么,对于区间[L,R]执行 swap 操作,其中的每个串 si 都会变成上述的形式;

      ∑(si) = 10*d*10f(sL)+sL*10+d 10*d*10f(sL+1)+sL+1*10+d +..........+ 10*d*10f(sR)+sR*10+d

          = 10*d*( 10f(sL)+10f(sL+1)+..........10f(sR)+10*(sL+sL+1+.......+sR)+(R-L+1)*d;

      得出这个表达式后,就可以用线段树进行区间维护了;

      线段树中定义的变量 :

    1 struct Seg
    2 {
    3     int l,r;
    4     ll f;
    5     ll sum;
    6     int mid(){return l+((r-l)>>1);}
    7     int len(){return r-l+1;};
    8 }seg[maxn<<2];

      (f = 10f(sl)+10f(sl+1)+..........10f(sr)  , sum=∑(si) for all l  i ≤ r)

      那么,对于修改的区间[l,r],更新f,sum操作如下(假设当前要修改的节点为pos):

    1 seg[pos].sum=10*d*seg[pos].f+10*seg[pos].sum+seg[pos].len()*d;
    2 seg[pos].f=seg[pos].f*100;

      线段树处理区间修改问题一定要用到懒惰标记,如何标记呢?

    1 struct Seg
    2 {
    3     ll lazyLen;
    4     ll lazyL;
    5     ll lazyR;
    6     int mid(){return l+((r-l)>>1);}
    7     int len(){return r-l+1;};
    8 }seg[maxn<<2];

      (lazyL : 左边懒惰的值 , lazyR : 右侧懒惰的值 , lazyLen : 懒惰的长度)  

      令 val = seg[pos].sum;

      假设 pos 节点依次懒惰了 d1,d2,d3,那么 lazyL = d3d2d1 , lazyR = d1d2d3 , lazyLen = 1000(103,共懒惰了三位);

       pushDown(pos)向下传递懒惰标记函数如下:

     1 void F(int son,int f)
     2 {
     3     seg[son].sum=(seg[f].lazyL*seg[f].lazyLen%mod*seg[son].f%mod+
     4                  seg[son].sum*seg[f].lazyLen%mod+
     5                  seg[son].len()*seg[f].lazyR%mod)%mod;
     6     seg[son].f=seg[son].f*seg[f].lazyLen%mod*seg[f].lazyLen%mod;
     7 
     8     seg[son].lazyL=(seg[f].lazyL*seg[son].lazyLen%mod+seg[son].lazyL)%mod;
     9     seg[son].lazyR=(seg[son].lazyR*seg[f].lazyLen%mod+seg[f].lazyR)%mod;
    10     seg[son].lazyLen=seg[son].lazyLen*seg[f].lazyLen%mod;
    11 }
    12 void pushDown(int pos)
    13 {
    14     Seg &tmp=seg[pos];
    15     if(tmp.lazyLen <= 1)
    16         return ;
    17 
    18     F(ls(pos),pos);
    19     F(rs(pos),pos);
    20 
    21     tmp.lazyLen=1;
    22     tmp.lazyL=tmp.lazyR=0;
    23 }

     AC代码:

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstring>
      4 using namespace std;
      5 #define ls(x) (x<<1)
      6 #define rs(x) (x<<1|1)
      7 #define ll long long
      8 const int mod=1e9+7;
      9 const int maxn=1e5+50;
     10  
     11 int n,m;
     12 struct Seg
     13 {
     14     int l,r;
     15     ll f;///10的幂和
     16     ll sum;///区间和
     17     ll lazyLen;
     18     ll lazyL;///左侧懒惰的数
     19     ll lazyR;///右侧懒惰的数
     20     int mid(){return l+((r-l)>>1);}
     21     int len(){return r-l+1;};
     22 }seg[maxn<<2];
     23  
     24 void pushUp(int pos)
     25 {
     26     seg[pos].f=(seg[ls(pos)].f+seg[rs(pos)].f)%mod;
     27     seg[pos].sum=(seg[ls(pos)].sum+seg[rs(pos)].sum)%mod;
     28 }
     29 void F(int son,int f)///向下传递懒惰标记
     30 {
     31     seg[son].sum=(seg[f].lazyL*seg[f].lazyLen%mod*seg[son].f%mod+
     32                  seg[son].sum*seg[f].lazyLen%mod+
     33                  seg[son].len()*seg[f].lazyR%mod)%mod;
     34     seg[son].f=seg[son].f*seg[f].lazyLen%mod*seg[f].lazyLen%mod;
     35  
     36     seg[son].lazyL=(seg[f].lazyL*seg[son].lazyLen%mod+seg[son].lazyL)%mod;
     37     seg[son].lazyR=(seg[son].lazyR*seg[f].lazyLen%mod+seg[f].lazyR)%mod;
     38     seg[son].lazyLen=seg[son].lazyLen*seg[f].lazyLen%mod;
     39 }
     40 void pushDown(int pos)
     41 {
     42     Seg &tmp=seg[pos];
     43     if(tmp.lazyLen <= 1)
     44         return ;
     45  
     46     F(ls(pos),pos);
     47     F(rs(pos),pos);
     48  
     49     tmp.lazyLen=1;
     50     tmp.lazyL=tmp.lazyR=0;
     51 }
     52 void buildSegTree(int l,int r,int pos)
     53 {
     54     seg[pos].l=l;
     55     seg[pos].r=r;
     56     seg[pos].lazyLen=1;
     57     seg[pos].lazyL=seg[pos].lazyR=0;
     58     if(l == r)
     59     {
     60         seg[pos].f=1;///初始为10^0
     61         seg[pos].sum=0;
     62         return ;
     63     }
     64     int mid=l+((r-l)>>1);
     65     buildSegTree(l,mid,ls(pos));
     66     buildSegTree(mid+1,r,rs(pos));
     67  
     68     pushUp(pos);
     69 }
     70 void Update(int l,int r,int pos,int d)
     71 {
     72     if(seg[pos].l == l && seg[pos].r == r)
     73     {
     74         seg[pos].sum=(10*d*seg[pos].f%mod+10*seg[pos].sum%mod+seg[pos].len()*d%mod)%mod;
     75         seg[pos].f=seg[pos].f*100%mod;
     76  
     77         seg[pos].lazyL=(d*seg[pos].lazyLen%mod+seg[pos].lazyL)%mod;
     78         seg[pos].lazyR=(seg[pos].lazyR*10+d)%mod;
     79         seg[pos].lazyLen=seg[pos].lazyLen*10%mod;
     80  
     81         return ;
     82     }
     83     pushDown(pos);
     84  
     85     int mid=seg[pos].mid();
     86     if(r <= mid)
     87         Update(l,r,ls(pos),d);
     88     else if(l > mid)
     89         Update(l,r,rs(pos),d);
     90     else
     91     {
     92         Update(l,mid,ls(pos),d);
     93         Update(mid+1,r,rs(pos),d);
     94     }
     95     pushUp(pos);
     96 }
     97 ll Query(int l,int r,int pos)
     98 {
     99     if(seg[pos].l == l && seg[pos].r == r)
    100         return seg[pos].sum;
    101  
    102     pushDown(pos);
    103  
    104     int mid=seg[pos].mid();
    105     if(r <= mid)
    106         return Query(l,r,ls(pos))%mod;///返回结果要取模
    107     else if(l > mid)
    108         return Query(l,r,rs(pos))%mod;
    109     else
    110         return (Query(l,mid,ls(pos))+Query(mid+1,r,rs(pos)))%mod;
    111 }
    112 void Solve()
    113 {
    114     buildSegTree(1,n,1);
    115  
    116     for(int i=1;i <= m;++i)
    117     {
    118         char order[10];
    119         int l,r,d;
    120         scanf("%s%d%d",order,&l,&r);
    121         if(order[0] == 'w')
    122         {
    123             scanf("%d",&d);
    124             Update(l,r,1,d);
    125         }
    126         else
    127             printf("%d
    ",Query(l,r,1));
    128     }
    129 }
    130 int main()
    131 {
    132     int test;
    133     scanf("%d",&test);
    134     for(int kase=1;kase <= test;++kase)
    135     {
    136         scanf("%d%d",&n,&m);
    137  
    138         printf("Case %d:
    ",kase);
    139         Solve();
    140     }
    141     return 0;
    142 }
    View Code

    刚开始,我的lazyLen记录的就是懒惰的长度,每次更新的时候都用个 quickPower(10,lazyLen),超时了..........

    调用quickPower()的次数太多了,每次 wrap 操作都要用到好多个quickPower();

  • 相关阅读:
    这2天参加WinHEC大会,园子里以有很多介绍,就不多说了,会上用手机录了一段windows 最新触摸屏操作技术演示,可以看看
    自启动U盘,一个会流行的好玩意
    为什么数据库导入是自动增量属性自动消失乐呢?
    网络带宽利用率的一般计算方法
    防止ARP病毒的一个小窍门
    Windows 系统补丁管理策略
    PDC大会就要召开了,园里有去的吗,看到一片文章,不知道windows7是否真的很好
    门户框架在项目和产品中的使用心得
    这段时间开发了一个共享软件,主要做IP资源管理的(SmartIPView),大家有兴趣可以看看,或给指点指点
    OpenGL自学教程1(窗口建立)
  • 原文地址:https://www.cnblogs.com/violet-acmer/p/10817571.html
Copyright © 2011-2022 走看看