【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 ...
随机推荐
- selenium自动化登录qq网页
一个简单的登录网页上qq的脚本,通过此脚本了解到有些位置是无法通过xpath来定位的反倒是By定位更方便 #encoding=utf-8 from selenium import webdriver ...
- 【转】ASP.NET Core 快速入门(环境篇)
原文链接:http://www.cnblogs.com/zhaopei/p/netcore.html [申明]:本人.NET Core小白.Linux小白.MySql小白.nginx小白.而今天要说是 ...
- Docker安装Zabbix全记录
零.Zabbix架构设计 一.docker安装mysql 查找Docker Hub上的mysql镜像: [root@10e131e69e15 ~]# docker search mysql INDEX ...
- LeetCode 234——回文链表
1. 题目 请判断一个链表是否为回文链表. 示例 1: 输入: 1->2 输出: false 示例 2: 输入: 1->2->2->1 输出: true 进阶: 你能否用 O( ...
- AMR无限增发代币至任意以太坊地址的漏洞利用及修复过程
AMR无限增发代币至任意以太坊地址的漏洞利用及修复过程 0x00 项目简述 Ammbr主要目标是打造具有高度弹性且易于连接的分布式宽带接入平台,同时降低上网相关成本.Ammbr打算创建具有人工智能和智 ...
- python完成简单购物功能
# # -*- coding: utf8 -*- # # Author:wxq # # date:2017/11/13 # # python 3.6 # 创建一个商品列表: product_lis = ...
- Daily Scrum02 12.04
第二轮迭代已经进行到了白热化阶段,大家在被编译搞的水深火热的同时依然没有忘记我们的具有颠覆性的团队项目.虽然第一轮迭代我们的成绩不错,但是一定要克服时间不充裕,任务互相冲突的困难,克服不可避免的舆论压 ...
- [译]如何根据条件从pandas DataFrame中删除不需要的行?
问题来源:https://stackoverflow.com/questions/13851535/how-to-delete-rows-from-a-pandas-dataframe-based-o ...
- lintcode-137-克隆图
137-克隆图 克隆一张无向图,图中的每个节点包含一个 label 和一个列表 neighbors. 数据中如何表示一个无向图?http://www.lintcode.com/help/graph/ ...
- Chrome Extension & Dark Theme
Chrome Extension & Dark Theme https://chrome.google.com/webstore/detail/eimadpbcbfnmbkopoojfekhn ...