【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
#include<iostream>
#include<string>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<map>
using namespace std;
typedef long long s64; const int ONE=;
const s64 Niyu=5e8+;
const int MOD=1e9+; int n,T;
int a[ONE*];
char ch[ONE];
int Q;
s64 x,y;
s64 x_orig,y_orig,x_bloc,y_bloc,diff;
s64 A,A_i; struct power
{
int len; struct point
{
s64 val,val_i;
friend point operator +(point a,point b)
{
a.val=(a.val + b.val)%MOD;
a.val_i=(a.val_i + b.val_i) % MOD;
return a;
}
}odd,eve; friend power operator +(power a,power b)
{
power c;
c.len = a.len+b.len;
if(a.len%)
{
c.odd = a.odd+b.eve;
c.eve = a.eve+b.odd;
}
else
{
c.odd = a.odd+b.odd;
c.eve = a.eve+b.eve;
}
return c;
}
}Node[ONE*],ZERO; s64 get()
{
s64 res=,Q=;char c;
while( (c=getchar())< || c> )
if(c=='-')Q=-;
if(Q) res=c-;
while( (c=getchar())>= && c<= )
res=res*+c-;
return res*Q;
} void Build(int i,int l,int r)
{
if(l==r)
{
Node[i].len = ;
Node[i].odd.val = a[l];
Node[i].odd.val_i = a[l]*l % MOD;
return;
} int mid=(l+r)/;
Build(i*,l,mid); Build(i*+,mid+,r); Node[i] = Node[i*] + Node[i*+];
} void Update(int i,int l,int r,int L,int x)
{
if(L==l && l==r)
{
Node[i].odd.val = x;
Node[i].odd.val_i = x*l % MOD;
Node[i].eve.val = Node[i].eve.val_i = ;
return;
} int mid=(l+r)/;
if(L<=mid) Update(i*,l,mid,L,x);
else Update(i*+,mid+,r,L,x); Node[i] = Node[i*] + Node[i*+];
} power Query(int i,int l,int r,int L,int R)
{
if(L>R) return ZERO;
if(L<=l && r<=R) return Node[i]; int mid=(l+r)/;
if(R<=mid) return Query(i*,l,mid,L,R);
if(mid+<=L) return Query(i*+,mid+,r,L,R);
return Query(i*,l,mid,L,R) + Query(i*+,mid+,r,L,R);
} s64 HE(s64 a,s64 b)
{
a--; b--;
if(a==b) return ;
if(a>b) return ;
s64 x=(b-a+) % MOD;
return (s64)(a+b)%MOD*x%MOD * Niyu % MOD;
} int main()
{
ZERO.len=; ZERO.odd.val=ZERO.odd.val_i=ZERO.eve.val=ZERO.eve.val_i=; n=get();
scanf("%s",ch+);
for(int i=;i<=n;i++) a[i]=ch[i]-'';
for(int i=;i<=n;i++) a[i+n]=a[i];
n*=; Build(,,n); T=get();
while(T--)
{
Q=get();
if(Q==)
{
x=get(); y=get();
Update(,,n,x,y);
Update(,,n,x+n/,y);
}
else
{
x=get(); y=get();
x_orig=(x-)%n+; y_orig=(y-)%n+;
x_bloc=(x-)/n+; y_bloc=(y-)/n+; diff = y_bloc-x_bloc-; diff%=MOD;
if(diff!=-)
{
if(x%)
{
power res_l = Query(,,n, x_orig,n);
power res_r = Query(,,n, ,y_orig);
power res_mid = Query(,,n, ,n); A =( res_l.odd.val + res_r.odd.val + res_mid.odd.val * diff % MOD ) % MOD;
A_i=; A_i += (res_l.odd.val_i + (s64)res_l.odd.val * (x_bloc-)%MOD * n % MOD)%MOD; A_i%=MOD;
A_i += (res_r.odd.val_i + (s64)res_r.odd.val * (y_bloc-)%MOD * n % MOD)%MOD; A_i%=MOD; A_i += (diff*res_mid.odd.val_i%MOD + (s64)res_mid.odd.val * n % MOD * HE(x_bloc+,y_bloc-)%MOD)%MOD;
A_i%=MOD;
}
else
{
power res_l = Query(,,n, x_orig,n);
power res_r = Query(,,n, ,y_orig);
power res_mid = Query(,,n, ,n); A =( res_l.odd.val + res_r.odd.val + res_mid.odd.val * diff % MOD ) % MOD;
A_i=; A_i += (res_l.odd.val_i + (s64)res_l.odd.val * (x_bloc-)%MOD * n % MOD)%MOD; A_i%=MOD;
A_i += (res_r.odd.val_i + (s64)res_r.odd.val * (y_bloc-)%MOD * n % MOD)%MOD; A_i%=MOD; A_i += (diff*res_mid.odd.val_i%MOD + (s64)res_mid.odd.val * n % MOD * HE(x_bloc+,y_bloc-)%MOD)%MOD;
A_i%=MOD;
}
}
else
{
power res = Query(,,n, x_orig,y_orig);
A = res.odd.val;
A_i=;
A_i += (s64)(res.odd.val_i + A * (x_bloc-)%MOD * n % MOD) % MOD; A_i%=MOD;
}
printf("%lld\n", (s64)(A * (y%MOD+) % MOD - A_i + MOD) % MOD);
}
} }
【FJWC2017】交错和查询 [线段树]的更多相关文章
- bzoj3110 [Zjoi2013]K大数查询——线段树套线段树
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3110 外层权值线段树套内层区间线段树: 之所以外层权值内层区间,是因为区间线段树需要标记下传 ...
- bzoj 3110 [Zjoi2013]K大数查询——线段树套线段树(标记永久化)
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3110 第一道线段树套线段树! 第一道标记永久化! 为什么为什么写了两个半小时啊…… 本想线段 ...
- [HDU-5172] 单点查询线段树
题意: 给你一个长度为n的数组v[],有m次询问,问你在区间[L,R]中是否包含区间[1,R-L+1]的全部数字,如果是输出YES,否则输出NO 题解: 区间[1,R-L+1]与区间[L,R]的长度一 ...
- 线段树 区间开方区间求和 & 区间赋值、加、查询
本文同步发表于 https://www.zybuluo.com/Gary-Ying/note/1288518 线段树的小应用 -- 维护区间开方区间求和 题目传送门 约定: sum(i,j) 表示区间 ...
- 序列内第k小查询(线段树)
最近请教了一下大佬怎么求序列内第k大查询,自己又捣鼓了一下,虽然还没有懂得区间第k大查询,不过姑且做一个记录先吧 因为每个元素大小可能很大而元素之间不连续,所以我们先离散化处理一下,程序中的ori[ ...
- hdu4831 Scenic Popularity(线段树)
题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=4831 题目大概意思就是有多个风景区和休息区,每个风景区有热度,休息区的热度与最接近的分景区的热度相同, ...
- HDU 3966 Aragorn's Story 树链剖分+树状数组 或 树链剖分+线段树
HDU 3966 Aragorn's Story 先把树剖成链,然后用树状数组维护: 讲真,研究了好久,还是没明白 树状数组这样实现"区间更新+单点查询"的原理... 神奇... ...
- POJ——3264线段树
题目: 输入两个数(m,n),m表示牛的头数,n表示查询的个数.查询时输入两个数(x,y),表示查询范围的起始值和终止值,查询结果是,这个区间内牛重量的最大值减去牛重量的最小值,数量级为1000,00 ...
- POJ1151-扫面线+线段树+离散化//入门题
比较水的入门题 记录矩形竖边的x坐标,离散化排序.以被标记的边建树. 扫描线段树,查询线段树内被标记的边.遇到矩形的右边就删除此边 每一段的面积是查询结果乘边的横坐标之差,求和就是答案 #includ ...
随机推荐
- springmvc+spring-data-jpa+hibernate环境搭建与配置
1.JPA诞生的缘由是为了整合第三方ORM框架,建立一种标准的方式,百度百科说是JDK为了实现ORM的天下归一,目前也是在按照这个方向发展,但是还没能完全实现.在ORM框架中,Hibernate是一支 ...
- Linux使用imagemagick的convert命令压缩图片,节省服务器空间
1,安装imagemagick yum install ImageMagick 2,获取图片 find ./ -regex '.*\(jpg\|JPG\|png\|jpeg\)' -size +500 ...
- 「日常训练」「小专题·图论」 Frogger (1-1)
题意 分析 变形的dijkstra. 分析题意之后补充. 代码 // Origin: // Theme: Graph Theory (Basic) // Date: 080518 // Author: ...
- 怎样安装Python3
在浏览器地址栏输入https://www.python.org/ 打开Python官网 好了,安装完成了! 可以把安装路径C:\Users\Administrator\AppData\Local\Pr ...
- Jenkins - 持续集成部署
1. 安装svn:用于checkout源码 (1)yum 安装:yum -y install subversion (2)查看svn版本信息:svnserver --version 2. 安装jdk ...
- python程序设计——基本语言特性
参考<Python程序设计(第2版)> 清华大学出版社 董付国 ##### 除特殊说明外,以下代码示例,均为python 3.6版本 ##### 一.Python语言特性 1.python ...
- HDFS伪分布式环境搭建
(一).HDFS shell操作 以上已经介绍了如何搭建伪分布式的Hadoop,既然环境已经搭建起来了,那要怎么去操作呢?这就是本节将要介绍的内容: HDFS自带有一些shell命令,通过这些命令我们 ...
- DP入门(2)——DAG上的动态规划
有向无环图(DAG,Directed Acyclic Graph)上的动态规划是学习动态规划的基础.很多问题都可以转化为DAG上的最长路.最短路或路径计数问题. 一.DAG模型 [嵌套矩形问题] 问题 ...
- C++STL——set
一.相关定义 set 集合,有唯一性,即每一个元素只有一个: 是一个有序的容器,里面的元素都是排序好的: 支持插入,删除,查找等操作. 注意 set中的元素可以是任意类型的,但是由于需要排序,所以元素 ...
- linux中升级安装python2.7
打算自建VPN,新购买了一个虚拟服务器,centOS6.6 自带的是python2.6,因为比较习惯python2.7,所以就升级到最新的python2.7.12 首先要安装:sudo yum ins ...