CodeForces121E 线段树上线段果
http://codeforces.com/problemset/problem/121/E
题意: Petya 喜欢幸运数,幸运数只包含 4 和 7 这两个数字。例如 47,744,4 都是幸运数字,但 5,16,467 不是。
Petya 有一个 N 个数的数组,他想给这个数组执行 M 个操作,可以分为两种操作:
add l r d把第 l 到 第 r 个数都加上 d;count l r统计第 l 到第 r 个数有多少个幸运数字。
喜闻乐见的数据结构题。
更加喜闻乐见的是这题能用树状数组直接暴力跑过去。对每一个区间修改进行n次单点修改的傻狗操作竟然也可以AC这题
#include <map>
#include <set>
#include <ctime>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
#define For(i, x, y) for(int i=x;i<=y;i++)
#define _For(i, x, y) for(int i=x;i>=y;i--)
#define Mem(f, x) memset(f,x,sizeof(f))
#define Sca(x) scanf("%d", &x)
#define Scl(x) scanf("%lld",&x);
#define Pri(x) printf("%d\n", x)
#define Prl(x) printf("%lld\n",x);
#define CLR(u) for(int i=0;i<=N;i++)u[i].clear();
#define LL long long
#define ULL unsigned long long
#define mp make_pair
#define PII pair<int,int>
#define PIL pair<int,long long>
#define PLL pair<long long,long long>
#define pb push_back
#define fi first
#define se second
typedef vector<int> VI;
const double eps = 1e-;
const int maxn = 1e5 + ;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + ;
int N,M,tmp,K;
const int sp[] = {,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,};
bool check[];
int a[maxn];
int tree[maxn];
void add(int t,int x){
for(;t <= N;t += t & -t){
tree[t] += x;
}
}
int getsum(int t){
int s = ;
for(;t;t -= t & -t){
s += tree[t];
}
return s;
}
int main()
{
For(i,,) check[sp[i]] = ;
scanf("%d%d",&N,&M);
For(i,,N){
int x; Sca(x); a[i] = x;
if(check[x]) add(i,);
}
For(i,,M){
int l,r;
char op[];
scanf("%s%d%d",op,&l,&r);
if(op[] == 'a'){
int d; Sca(d);
For(j,l,r){
if(check[a[j]]) add(j,-);
a[j] += d;
if(check[a[j]]) add(j,);
}
}else{
Pri(getsum(r) - getsum(l - ));
}
}
#ifdef VSCode
system("pause");
#endif
return ;
}
当然正解肯定不是这样的
困难之处在于维护区间内幸运数字的个数。事实上确实不简单,思路和hdu多校里面的一道线段树相似。
线段树维护三个值,区间内所有数到下一个幸运数字差值的最小值,最小值的个数,lazy标记
每一次update之后要重新遍历一次线段树去寻找有没有最小值小于0的数,然后将这些减少到0的数一个个修改即可。
看起来很麻烦的操作事实上时间复杂度是很科学的正解。
#include <map>
#include <set>
#include <ctime>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
#define For(i, x, y) for(int i=x;i<=y;i++)
#define _For(i, x, y) for(int i=x;i>=y;i--)
#define Mem(f, x) memset(f,x,sizeof(f))
#define Sca(x) scanf("%d", &x)
#define Scl(x) scanf("%lld",&x);
#define Pri(x) printf("%d\n", x)
#define Prl(x) printf("%lld\n",x);
#define CLR(u) for(int i=0;i<=N;i++)u[i].clear();
#define LL long long
#define ULL unsigned long long
#define mp make_pair
#define PII pair<int,int>
#define PIL pair<int,long long>
#define PLL pair<long long,long long>
#define pb push_back
#define fi first
#define se second
inline LL read(){LL now=;register char c=getchar();for(;!isdigit(c);c=getchar());
for(;isdigit(c);now=now*+c-'',c=getchar());return now;}
inline void out(int x){if(x > ) out(x / ); putchar(x % + '');}
inline void out(LL x){if(x > ) out(x / ); putchar(x % + '');}
typedef vector<int> VI;
const double eps = 1e-;
const int maxn = 1e5 + ;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + ;
int N,M,tmp,K;
const int sp[] = {,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,};
struct Tree{
int l,r;
int x,y,lazy;
}tree[maxn * ];
int c[maxn];
int a[maxn];
void Pushup(int t){
if(tree[t << ].x == tree[t << | ].x){
tree[t].x = tree[t << ].x;
tree[t].y = tree[t << ].y + tree[t << | ].y;
}else if(tree[t << ].x < tree[t << | ].x){
tree[t].x = tree[t << ].x;tree[t].y = tree[t << ].y;
}else{
tree[t].x = tree[t << | ].x;tree[t].y = tree[t << | ].y;
}
}
void Build(int t,int l,int r){
tree[t].l = l; tree[t].r = r;
tree[t].lazy = ;
if(l == r){
tree[t].x = c[a[l]];
tree[t].y = ;
return;
}
int m = (l + r) >> ;
Build(t << ,l,m); Build(t << | ,m + ,r);
Pushup(t);
}
void Pushdown(int t){
if(tree[t].lazy){
tree[t << ].lazy += tree[t].lazy;
tree[t << | ].lazy += tree[t].lazy;
tree[t << ].x += tree[t].lazy;
tree[t << | ].x += tree[t].lazy;
tree[t].lazy = ;
}
}
void update(int t,int l,int r,int val){
if(l <= tree[t].l && tree[t].r <= r){
tree[t].x += val;
tree[t].lazy += val;
return;
}
Pushdown(t);
int m = (tree[t].l + tree[t].r) >> ;
if(r <= m) update(t << ,l,r,val);
else if(l > m) update(t << | ,l,r,val);
else{
update(t << ,l,m,val); update(t << | ,m + ,r,val);
}
Pushup(t);
} void rebuild(int t){
if(tree[t].x >= ) return;
if(tree[t].l == tree[t].r){
a[tree[t].l] -= tree[t].lazy;
tree[t].x = c[a[tree[t].l]];
tree[t].lazy = ;
return ;
}
Pushdown(t);
rebuild(t << ); rebuild(t << | );
Pushup(t);
}
int query(int t,int l,int r){
if(tree[t].x) return ;
if(l <= tree[t].l && tree[t].r <= r){
return tree[t].y;
}
Pushdown(t);
int m = (tree[t].l + tree[t].r) >> ;
if(r <= m) return query(t << ,l,r);
if(l > m) return query(t << | ,l,r);
else return query(t << ,l,m) + query(t << | ,m + ,r);
}
int main()
{
int cnt = ;
For(i,,1e4){
if(sp[cnt] < i) cnt++;
c[i] = sp[cnt] - i;
}
N = read(); M = read();
For(i,,N) a[i] = read();
Build(,,N);
int l,r;
char op[];
For(i,,M){
scanf("%s",op);
l = read(); r = read();
if(op[] == 'a'){
int d; d = read();
update(,l,r,-d);
rebuild();
}else{
out(query(,l,r));
puts("");
}
}
#ifdef VSCode
system("pause");
#endif
return ;
}
CodeForces121E 线段树上线段果的更多相关文章
- Naive Operations HDU多校(线段树上线段果)
Problem Description In a galaxy far, far away, there are two integer sequence a and b of length n.b ...
- LOJ 3059 「HNOI2019」序列——贪心与前后缀的思路+线段树上二分
题目:https://loj.ac/problem/3059 一段 A 选一个 B 的话, B 是这段 A 的平均值.因为 \( \sum (A_i-B)^2 = \sum A_i^2 - 2*B \ ...
- 贪心+离散化+线段树上二分。。。 Samara University ACM ICPC 2016-2017 Quarterfinal Qualification Contest G. Of Zorcs and Axes
题目链接:http://codeforces.com/gym/101149/problem/G 题目大意:给你n对数字,为(a[i], b[i]),给你m对数字,为(w[i], c[i]).给n对数字 ...
- 【BZOJ】4293: [PA2015]Siano 线段树上二分
[题意]给定n棵高度初始为0的草,每天每棵草会长高a[i],m次收割,每次在d[i]天将所有>b[i]的草收割到b[i],求每次收割量.n<=500000. [算法]线段树上二分 [题解] ...
- hdu 5930 GCD 线段树上二分/ 强行合并维护信息
from NOIP2016模拟题28 题目大意 n个点的序列,权值\(<=10^6\) q个操作 1.单点修改 2.求所有区间gcd中,不同数个数 分析 1.以一个点为端点,向左或向右的gcd种 ...
- HDU 4747 Mex【线段树上二分+扫描线】
[题意概述] 一个区间的Mex为这个区间没有出现过的最小自然数,现在给你一个序列,要求求出所有区间的Mex的和. [题解] 扫描线+线段树. 我们在线段树上维护从当前左端点开始的前缀Mex,显然从左到 ...
- [NOIP2015模拟10.27] [JZOJ4270] 魔道研究 解题报告(动态开点+权值线段树上二分)
Description “我希望能使用更多的魔法.不对,是预定能使用啦.最终我要被大家称呼为大魔法使.为此我决定不惜一切努力.”——<The Grimoire of Marisa>雾雨魔理 ...
- 【2019.8.6 慈溪模拟赛 T3】集合(set)(线段树上DP)
线段树上\(DP\) 首先发现,每个数肯定是向自己的前驱或后继连边的. 则我们开一棵权值线段树,其中每一个节点记录一个\(f_{0/1,0/1}\),表示在这个区间左.右端点是否连过边的情况下,使这个 ...
- 【洛谷5537】【XR-3】系统设计(哈希_线段树上二分)
我好像国赛以后就再也没有写过 OI 相关的博客 qwq Upd: 这篇博客是 NOIP (现在叫 CSP 了)之前写的,但是咕到 CSP 以后快一个月才发表 -- 我最近这么咕怎么办啊 -- 题目 洛 ...
随机推荐
- dom定位的三种元素
1.通过id #XXX 2.通过标签 xxx 3.通过类 .xxx
- 在 ubuntu 中安装 python3.5、 tornado、 pymysql
一.在 ubuntu 中安装 python3.5 1.首先,在系统中是自带python2.7的.不要卸载,因为一些系统的东西是需要这个的.python2.7和python3.5是可以共存的. 命令如下 ...
- SpringMVC 复杂对象数据绑定
表单在 web 页面上无处不在,有些表单可能很复杂,大部分表单里的输入项都会对应后端对象属性.SpringMVC 可以自动将表单值绑定到对象上!而且能绑定很复杂的对象!!这里就不写那些基本的表单绑定了 ...
- The Embarrassed Cryptographer POJ - 2635 同余模+高精度处理 +线性欧拉筛(每n位一起处理)
题意:给出两数乘积K(1e100) 和 一个数L(1e6) 问有没有小于L(不能等于)的素数是K的因数 思路:把数K切割 用1000进制表示 由同余模公式知 k%x=(a*1000%x+b* ...
- 大学实验3指导:利用单链表实现A-B
实验目的:深入理解单链表的建立及操作 实验内容: 1.建立单链表A与B 2.实现主要的函数,查找.插入.删除等 3.实现操作A-B 步骤1:包含必要的函数库,对结构体LNode中的抽象数据类型Elem ...
- Spring02-注入和注解方式操作
一. 依赖注入 测试类:Person.java 创建配置文件:applicationContext-injection.xml 创建测试代码:InjectionTest.java 1. set方法注入 ...
- FPGA中亚稳态相关问题及跨时钟域处理
前言 触发器输入端口的数据在时间窗口内发生变化,会导致时序违例.触发器的输出在一段时间内徘徊在一个中间电平,既不是0也不是1.这段时间称为决断时间(resolution time).经过resolut ...
- 【XSY2472】string KMP 期望DP
题目大意 给定一个由且仅由字符'H','T'构成的字符串\(S\). 给定一个最初为空的字符串\(T\) ,每次随机地在\(T\)的末尾添加'H'或者'T'. 问当\(S\)为\(T\)的后缀时, ...
- php获取用户真实IP和防刷机制
一. 如何获取用户IP地址 public static function getClientIp() { if (getenv('HTTP_CLIENT_IP')) { $ip = getenv( ...
- emwin之2D图形流位图显示的方法
@2018-10-31 [需求] 界面上绘制状态指示图标 [方法] --① 方法一 外部存储介质上的图标读写与显示 i . 将要显示的图标使用官方软件<BmpCvt.exe>转换成 &q ...