SMOJ 转盘/P6357 COCI 2007/2008 #3 REDOKS 题解

ops/2025/2/21 5:43:31/

题意

给定一串长度为 n n n 的数字,数字为 0 ∼ 9 0\sim 9 09 之间的任意一个,下标从 1 1 1 记起。

然后进行 m m m 次区间查询,每次查找区间 [ A , B ] [A,B] [A,B] 的区间和,并在查询结束后将区间里的每一个数都 + 1 +1 +1。特殊地,如果 + 1 +1 +1 前的数字为 9 9 9,那么 + 1 +1 +1 之后就变成了 0 0 0

请输出每次查询的区间和。

思路

前面做过那么多势能线段树,肯定想要用势能线段树来做。然而发现这是一个区间修改(区间加),那 p u s h d o w n pushdown pushdown 要怎么办呢?如果要写 p u s h d o w n pushdown pushdown 就很难搞最大值,而且修改次数就是 m m m 次, m m m 次都可能干上最大值 10 10 10 ;如果不写 p u s h d o w n pushdown pushdown,等着我们的就是T飞!

但是我们发现,数字出现的范围是 0 ∼ 9 0\sim 9 09,非常少,用一个桶来维护绰绰有余。

于是我们考虑维护区间中 0 ∼ 9 0\sim 9 09 分别有多少个的桶 c n t cnt cnt 数组就好了。引入懒标记 t a g tag tag 表示修改次数,每次修改操作把该区间的 t a g + 1 tag+1 tag+1 ,做一次修改即可。

对于 u u u 区间的修改,要进行 k k k 次修改,集成为一个函数 m o d i modi modi :每次先把原来桶复制一份到 t e m tem tem 数组,然后把按照 0 ∼ 9 0\sim 9 09的顺序顺次加 k k k 10 10 10 进行移位操作。 c n t ( i + k ) m o d 10 ← t e m i , i ∈ [ 0 , 9 ] cnt_{(i+k)\mod 10}\leftarrow tem_i,\ i\in[0,9] cnt(i+k)mod10temi, i[0,9]

void modi(ll u,ll k)
{if(k==0)return;for(int i=0;i<P;i++)tem[i]=T[u].cnt[i],T[u].cnt[i]=0;for(int i=0;i<P;i++)T[u].cnt[(i+k)%P]=tem[i];
}

那么其他就是线段树的基本操作了。建树时每个数位上的数,桶置为 1 1 1 即可。

代码

#include<bits/stdc++.h>
using namespace std;
#define ll int
#define ls u<<1
#define rs u<<1|1
const ll N=2.5e5+2,M=1e6+9,P=10;
ll n,m,a[N],tem[P+1];
char c[N];
struct SegT
{struct node{ll cnt[12],tag;}T[N<<4];void modi(ll u,ll k){if(k==0)return;for(int i=0;i<P;i++)tem[i]=T[u].cnt[i],T[u].cnt[i]=0;for(int i=0;i<P;i++)T[u].cnt[(i+k)%P]=tem[i];}void pushup(ll u){for(int i=0;i<=9;i++)T[u].cnt[i]=T[ls].cnt[i]+T[rs].cnt[i]; }void pushdown(ll u){if(T[u].tag){T[ls].tag+=T[u].tag;modi(ls,T[u].tag);T[rs].tag+=T[u].tag;modi(rs,T[u].tag);T[u].tag=0;}}void build(ll u,ll l,ll r){if(l==r){T[u].cnt[a[l]]=1;return;}ll mid=(l+r)>>1;build(ls,l,mid);build(rs,mid+1,r);pushup(u);}void modify(ll u,ll l,ll r,ll ql,ll qr){if(qr<l||r<ql)return;if(ql<=l&&r<=qr){T[u].tag++;modi(u,1);return;}ll mid=(l+r)>>1;pushdown(u);if(ql<=mid)modify(ls,l,mid,ql,qr);if(qr>mid)modify(rs,mid+1,r,ql,qr);pushup(u);}ll query(ll u,ll l,ll r,ll ql,ll qr){if(qr<l||r<ql)return 0;if(ql<=l&&r<=qr){ll ret=0;for(int i=0;i<=9;i++)ret+=T[u].cnt[i]*i;return ret;}ll mid=(l+r)>>1,ret=0;pushdown(u);if(ql<=mid)ret+=query(ls,l,mid,ql,qr);if(qr>mid)ret+=query(rs,mid+1,r,ql,qr);return ret;}
}A;
int main()
{scanf("%d%d%s",&n,&m,c+1);for(int i=1;i<=n;i++)a[i]=c[i]-'0';A.build(1,1,n);while(m--){ll l,r;scanf("%d%d",&l,&r);printf("%d\n",A.query(1,1,n,l,r));A.modify(1,1,n,l,r);}return 0;
}

http://www.ppmy.cn/ops/159721.html

相关文章

spark任务运行

运行环境 在这里插入代码片 [roothadoop000 conf]# java -version java version "1.8.0_144" Java(TM) SE Runtime Environment (build 1.8.0_144-b01)[roothadoop000 conf]# echo $JAVA_HOME /home/hadoop/app/jdk1.8.0_144[roothadoop000 conf]# vi spark-env.sh …

电力交易员需要哪些证书

电力交易员职业资格证书 电力交易员国家职业资格证书 &#xff1a;这是电力交易员的从业资格证书&#xff0c;由国家职业资格鉴定机构颁发&#xff0c;分为初级、中级、高级和高级技师四个等级。该证书是电力交易员专业技能和职业素养的重要证明&#xff0c;有助于提升就业竞争…

常见的缓存更新策略

Cache Aside Pattern&#xff08;旁路缓存模式&#xff09; Cache Aside Pattern 是我们平时使用比较多的一个缓存读写模式&#xff0c;比较适合读请求比较多的场景。 读写步骤 写: 更新DB删除缓存 读: 缓存读数据&#xff0c;读到直接返回未读取到直接从db读取db读取的数据同…

深入理解 fnmatch 函数的实现

0、背景 fnmatch 函数是 C 标准库和 POSIX 中用于匹配文件路径的工具&#xff0c;它使得我们能够根据模式字符串对文件名进行模式匹配。常见的用途包括在文件系统中查找符合某种模式&#xff08;如通配符&#xff09;的文件。例如&#xff0c;fnmatch(“.txt", “file1.t…

DeepSeek VS OpenAI:AI巨头应用对比

DeepSeek 和 OpenAI 都是领先的 AI 公司&#xff0c;具备各自的优势。这两天我读了一篇很棒的文章&#xff0c;作者Da-vinci对这两家AI巨头做了很直观的介绍比较。以下是来自原创的部分内容&#xff1a; DeepSeek、ChatGPT 比较表 DeepSeek、ChatGPT 比较表 | 来源于Da-vinci …

高速硬件电路设计

高速PCB 设计三大原则 3W原则 **1.定义&#xff1a;**线和线之间的距离保持3倍线宽。 2.作用&#xff1a;减少线间的串扰&#xff0c;可以保证70%的线间电场不互相干扰 3.总结&#xff1a;高速信号3W规则走&#xff0c;低速信号最低2W 20H 原则 1.图1&#xff0c;电源层和地…

Unity 打开摄像头 并显示在UI

需求: 打开相机并显示在UI上 效果: 注意&#xff1a; 电脑可能有多个摄像头&#xff0c;注意名称 代码: using System; using System.Linq; using UnityEngine; using UnityEngine.UI; using System.Collections.Generic; #if UNITY_EDITOR using UnityEditor; #endifname…

【Scrapy】Scrapy教程5——第一个Scrapy项目

文章目录 Scrapy目录结构第一个爬虫运行爬虫必要说明start_requests()和start_urls如何关闭allowed_domains的限制通过前几节的学习,我们已经了解了Scrapy的基本操作,下面我们开始第一个项目,我以本人的 网址为例进行爬虫讲解,之所以用我自己的网站,是因为我这个网站本来…