zoukankan      html  css  js  c++  java
  • 【FJWC2017】交错和查询 [线段树]

    交错和查询

    Time Limit: 10 Sec  Memory Limit: 256 MB

    Description

      无限循环数字串S由长度为n的循环节s构成。设s为12345(n=5),则数字串S为123451234512345…
      设Si为S的第i位数字,在上面的例子中,S1=1,S2=2,S6=1。
      设S的一个子串S[l,r]的交错和为sum(l,r):
      sum(l,r) = Sl - S1+1 + Sl+2- Sl+3 + … + (-1)r-lSr
      如sum(2,7) = 2 - 3 + 4 - 5 + 1 - 2 = -3
      现给定循环节s,要求支持两种操作:
      1 pos digit:修改循环节s上的某一位,即将spos改为digit。
      2 l r:求S[l,r]内所有子串的交错和的和,即输出ans对10^9+7的模。

    Input

      第一行一个整数n,表示循环节s的长度。
      第二行一个长度为n的数字串,表示循环节s。
      第三行一个整数m,表示操作次数。
      以下m行,每行3个整数。
      若第一个数为1,表示是修改操作1 pos digit。
      若第一个数为2,表示是询问操作2 l r。

    Output

      对于每个询问操作输出一行,表示答案。

    Sample Input 

      5
      12345
      5
      2 1 5
      2 6 10
      1 3 5
      2 1 5
      2 1 6

    Sample Output

      19
      19
      25
      36

    HINT

      对于10%的数据点,n, m <= 50;
      对于20%的数据点,n, m <=1000;
      对于40%的数据点,1 <= l<= r <= n;
      对于100%的数据点,n, m <=200000;1 <= l <= r <= 1018;1 <= pos <= n;0 <= digit <= 9;

    Main idea

      给定两种操作:1.修改循环节上的某一位;2.询问[l,r]的所有子串和。 

    Solution

      首先轻易地找到了规律,发现对于区间[l,r],只有奇数位置上的值会对答案产生影响,并且:,然后我们拆开式子得到:。现在考虑如何用一个数据结构来维护这个Ans,这里采用线段树

      我们分几步来实现:

      第一步:
      我们先考虑l,r在一个循环节内的情况。显然对于线段树上的每个节点维护五个信息:len, odd.val, odd.val_i, eve.val, eve.val_i分别表示区间长度、奇数位置的和、奇数位置*i的和、偶数位置的和、偶数位置*i的和,那么我们上传合并线段树的时候判断一下区间长度的奇偶即可。举个例子:比如现在左区间长度为3,要更新奇数位置的值,就是左区间的奇数位置和 加上 右区间的偶数位置和,我们重载运算符判断一下即可。这样操作我们就可以得到Σai以及Σai*i。

      第二步:
      (1)  我们再来考虑一下l,r不在一个循环节内的情况。显然我们可以将区间拆成三部分:左段、中段、右段,其中中段是包含所有的1-n的整体,而左段和右段则是~n或者1~的一部分

      (2)  然后我们显然可以很轻易地通过计算一下x,y的间隔块数以及若干信息来算出Σai。

      (3)  那么式子后面的Σai*i怎么办呢?我们发现:我们将序列分为若干段,显然每一段增加的值是一样的,那么我们就可以将Σai*i(这里的i是实际位置)拆成:Σai*i (在一个循环节中的位置) + Σai*(所在块数-1)*n。

      (4)  然后我们中段块数一定不为1,要怎么办呢?举个例子,比如循环节长度为10,我们要求2~4段的Σ,那么显然就是Σai*n*(i+1+2),惊讶地发现中间的一个等差数列,那么我们要乘的就是一个等差数列的和了。

      (5)  然后三段中到底是统计奇数位置的和还是统计偶数位置的和呢?发现较难处理,于是我们可以将原序列*2(拓展一倍),发现如果x是奇数,那么就加上左段的奇数位置,中段右段的奇数位置,否则加上左段的奇数位置,以及中段右段的偶数位置。

      这样我们就解决了问题,具体问题还是参见代码啦。

    Code

      1 #include<iostream>     
      2 #include<string>     
      3 #include<algorithm>     
      4 #include<cstdio>     
      5 #include<cstring>     
      6 #include<cstdlib>     
      7 #include<cmath>     
      8 #include<map>   
      9 using namespace std;   
     10 typedef long long s64;
     11 
     12 const int ONE=200001;
     13 const s64 Niyu=5e8+4;
     14 const int MOD=1e9+7;
     15 
     16 int n,T;
     17 int a[ONE*2];
     18 char ch[ONE];
     19 int Q;
     20 s64 x,y;
     21 s64 x_orig,y_orig,x_bloc,y_bloc,diff;
     22 s64 A,A_i;
     23 
     24 struct power
     25 {
     26         int len;
     27         
     28         struct point
     29         {
     30             s64 val,val_i;
     31             friend point operator +(point a,point b)
     32             {
     33                 a.val=(a.val + b.val)%MOD;
     34                 a.val_i=(a.val_i + b.val_i) % MOD;
     35                 return a; 
     36             }
     37         }odd,eve;
     38         
     39         friend power operator +(power a,power b)
     40         {
     41             power c;
     42             c.len = a.len+b.len;
     43             if(a.len%2)
     44             {
     45                 c.odd = a.odd+b.eve;
     46                 c.eve = a.eve+b.odd;
     47             }
     48             else
     49             {
     50                 c.odd = a.odd+b.odd;
     51                 c.eve = a.eve+b.eve;
     52             }
     53             return c;
     54         }
     55 }Node[ONE*10],ZERO;
     56 
     57 s64 get()     
     58 {     
     59         s64 res=1,Q=1;char c;     
     60         while( (c=getchar())<48 || c>57 )  
     61         if(c=='-')Q=-1;  
     62         if(Q) res=c-48;      
     63         while( (c=getchar())>=48 && c<=57 )     
     64         res=res*10+c-48;     
     65         return res*Q;     
     66 }
     67 
     68 void Build(int i,int l,int r)
     69 {
     70         if(l==r)
     71         {
     72             Node[i].len = 1;
     73             Node[i].odd.val = a[l];
     74             Node[i].odd.val_i = a[l]*l % MOD;
     75             return;
     76         }
     77         
     78         int mid=(l+r)/2;
     79         Build(i*2,l,mid); Build(i*2+1,mid+1,r);
     80         
     81         Node[i] = Node[i*2] + Node[i*2+1];
     82 }
     83 
     84 void Update(int i,int l,int r,int L,int x)
     85 {
     86         if(L==l && l==r)
     87         {
     88             Node[i].odd.val = x;
     89             Node[i].odd.val_i = x*l % MOD;
     90             Node[i].eve.val = Node[i].eve.val_i = 0;
     91             return;
     92         }
     93         
     94         int mid=(l+r)/2;
     95         if(L<=mid) Update(i*2,l,mid,L,x);
     96         else Update(i*2+1,mid+1,r,L,x);
     97         
     98         Node[i] = Node[i*2] + Node[i*2+1];
     99 }
    100 
    101 power Query(int i,int l,int r,int L,int R)
    102 {
    103         if(L>R) return ZERO;
    104         if(L<=l && r<=R) return Node[i];
    105         
    106         int mid=(l+r)/2;
    107         if(R<=mid) return Query(i*2,l,mid,L,R);
    108         if(mid+1<=L) return Query(i*2+1,mid+1,r,L,R);
    109         return Query(i*2,l,mid,L,R) + Query(i*2+1,mid+1,r,L,R);
    110 }
    111 
    112 s64 HE(s64 a,s64 b)
    113 {
    114         a--;    b--;
    115         if(a==b) return 1;
    116         if(a>b) return 0;
    117         s64 x=(b-a+1) % MOD;
    118         return (s64)(a+b)%MOD*x%MOD * Niyu % MOD;
    119 }
    120 
    121 int main()
    122 {
    123         ZERO.len=1; ZERO.odd.val=ZERO.odd.val_i=ZERO.eve.val=ZERO.eve.val_i=0;
    124         
    125         n=get();
    126         scanf("%s",ch+1);
    127         for(int i=1;i<=n;i++) a[i]=ch[i]-'0';
    128         for(int i=1;i<=n;i++) a[i+n]=a[i];
    129         n*=2;    Build(1,1,n);
    130         
    131         T=get();
    132         while(T--)
    133         {
    134             Q=get();
    135             if(Q==1)
    136             {
    137                 x=get();    y=get();
    138                 Update(1,1,n,x,y);
    139                 Update(1,1,n,x+n/2,y);
    140             }
    141             else
    142             {
    143                 x=get();    y=get();
    144                 x_orig=(x-1)%n+1;    y_orig=(y-1)%n+1;
    145                 x_bloc=(x-1)/n+1;    y_bloc=(y-1)/n+1;
    146                 
    147                 diff = y_bloc-x_bloc-1;    diff%=MOD;
    148                 if(diff!=-1)
    149                 {
    150                     if(x%2)
    151                     {
    152                         power res_l = Query(1,1,n, x_orig,n);
    153                         power res_r = Query(1,1,n, 1,y_orig);
    154                         power res_mid = Query(1,1,n, 1,n);
    155                         
    156                         A =( res_l.odd.val + res_r.odd.val + res_mid.odd.val * diff % MOD ) % MOD;
    157                         A_i=0;
    158                         
    159                         A_i += (res_l.odd.val_i + (s64)res_l.odd.val * (x_bloc-1)%MOD * n % MOD)%MOD; A_i%=MOD;
    160                         A_i += (res_r.odd.val_i + (s64)res_r.odd.val * (y_bloc-1)%MOD * n % MOD)%MOD; A_i%=MOD;
    161                         
    162                         A_i += (diff*res_mid.odd.val_i%MOD + (s64)res_mid.odd.val * n % MOD * HE(x_bloc+1,y_bloc-1)%MOD)%MOD;
    163                         A_i%=MOD;
    164                     }
    165                     else
    166                     {
    167                         power res_l = Query(1,1,n, x_orig,n);
    168                         power res_r = Query(1,1,n, 2,y_orig);
    169                         power res_mid = Query(1,1,n, 2,n);
    170                         
    171                         A =( res_l.odd.val + res_r.odd.val + res_mid.odd.val * diff % MOD ) % MOD;
    172                         A_i=0;
    173                         
    174                         A_i += (res_l.odd.val_i + (s64)res_l.odd.val * (x_bloc-1)%MOD * n % MOD)%MOD; A_i%=MOD;
    175                         A_i += (res_r.odd.val_i + (s64)res_r.odd.val * (y_bloc-1)%MOD * n % MOD)%MOD; A_i%=MOD;
    176                         
    177                         A_i += (diff*res_mid.odd.val_i%MOD + (s64)res_mid.odd.val * n % MOD * HE(x_bloc+1,y_bloc-1)%MOD)%MOD;
    178                         A_i%=MOD;
    179                     }
    180                 }
    181                 else
    182                 {
    183                     power res = Query(1,1,n, x_orig,y_orig);
    184                     A = res.odd.val;
    185                     A_i=0;
    186                     A_i += (s64)(res.odd.val_i + A * (x_bloc-1)%MOD * n % MOD) % MOD; A_i%=MOD;
    187                 }
    188                 printf("%lld
    ", (s64)(A * (y%MOD+1) % MOD - A_i + MOD) % MOD);
    189             }
    190         }
    191         
    192 }
    View Code
  • 相关阅读:
    其实很简单——SpringIOC详解
    设计模式之原型模式与深拷贝、浅拷贝
    《Understanding the JVM》读书笔记之五——类加载器
    《Understanding the JVM》读书笔记之四——类加载机制
    《Understanding the JVM》读书笔记之三——垃圾收集器
    《Understanding the JVM》读书笔记之二——垃圾回收算法
    《Understanding the JVM》读书笔记之一——JVM内存模型
    开始实现功能(一)——用户模块,从注册登录开始
    网站后台搭建--springboot项目是如何创建的
    从网站功能入手创建数据库
  • 原文地址:https://www.cnblogs.com/BearChild/p/6440737.html
Copyright © 2011-2022 走看看