JZOJ.5289【NOIP2017模拟8.17】偷笑
2017-08-18 07:42
190 查看
Description
berber走进机房,边敲门边喊:“我是哔哔”CRAZY转过头:“我警告你,哔哔刚刚来过!”
“呵呵呵呵……”
这时,哔哔站了起来,环顾四周:“你们笑什么?……”
巧了,发出笑声的人都排成了一排,每个人刚开始发出的笑声值为a[i]的笑声。但是有些笑声哔哔是听不出来的,他只听得出笑声值只包含2和3的数字,比如说什么2333。
但是同学们还是很会秀操作的。对于操作add l r x表示l到r的同学的笑声值同时加上x。数据保证操作完的x在2*10^4以内。
但是,哔哔还是很想知道哪些人在笑。对于count l r表示询问l到r的同学中有多少个笑声值是哔哔听得出来的(就是只由2和3组成)。
哔哔是很忙的,他需要坐在旁边的你来帮他完成这个问题。
Input
第一行两个整数分别为n,m表示同学的数目和操作数。第二行n个整数a[i]表示同学一开始的笑声值。接下来m行表示操作数,描述如上。Output
按照题目输出答案。Sample Input
3 6 2 3 4 count 1 3 count 1 2 add 1 3 2 count 1 3 add 2 3 3 count 1 3
Sample Output
2 2 0 0
Data Constraint
对于20%的数据n,m≤2000对于另外30%的数据n,m≤50000
对于另外50%的数据n,m≤300000
本题时限3s
题意就是区间修改和区间查询,其中查询是某区间内不含2,3以外的数的个数。
区间修改我们可以用线段树来维护,但问题就在查询。线段树查询并不支持直接查询题目要求的数的个数,我们虽然可以一个一个检查,但除法取模运算相比也比较慢,每次查询的nlogn复杂度也接受不了。
直接维护不好做,我们可以尝试改变一下线段树维护的信息。
我们注意到题目给出的a[i]的最大值不会超过20000,在20000内符合题目的233数一共也只有31个,我们可以预处理这些,然后维护每个数a[i]与这些数相差最小的且比a[i]大的数的差值,很明显,当差值为0的时候就说明它是个233数,如果差值小于0,我们就要找下一个比它大且相差最小的233数,作差比较,由于每个数最多被修改31次,所以复杂度为O(31mlogn)
#include<iostream> #include<cstdio> #include<cstring> #include<ctime> #define N 1600000 using namespace std; struct data{ int cnt,min,mark; }tree ; int f[32]={2,3,22,23,32,33,222,223,232,233,322,323,332,333,2222,2223,2232,2233,2322,2323,2332,2333,3222,3223,3232,3233,3322,3323,3332,3333,22222}; int n,m,voi[N/4],x,y,z,top[N/4]; char str[10]; void build(int root,int l,int r){ tree[root].mark=0; if (l==r){ while (f[top[l]]<voi[l]) top[l]++; tree[root].min=f[top[l]]-voi[l]; if (tree[root].min==0) tree[root].cnt=1; return; } int mid=(l+r)>>1; build(root<<1,l,mid); build(root<<1|1,mid+1,r); tree[root].min=min(tree[root<<1].min,tree[root<<1|1].min); tree[root].cnt=tree[root<<1].cnt+tree[root<<1|1].cnt; } void pushdown(int root,int l,int r){ if (tree[root].mark){ tree[root<<1].mark+=tree[root].mark; tree[root<<1|1].mark+=tree[root].mark; tree[root<<1].min+=tree[root].mark; tree[root<<1|1].min+=tree[root].mark; tree[root].mark=0; } return; } void updata(int root,int l,int r){ if (tree[root].min>0) return; if (l==r){ if (tree[root].min<0){ voi[l]-=tree[root].mark; tree[root].mark=0; while (f[top[l]]<voi[l]) top[l]++; tree[root].min=f[top[l]]-voi[l]; } if (tree[root].min==0) tree[root].cnt=1; else tree[root].cnt=0; return; } pushdown(root,l,r); int mid=(l+r)>>1; updata(root<<1,l,mid); updata(root<<1|1,mid+1,r); tree[root].min=min(tree[root<<1].min,tree[root<<1|1].min); tree[root].cnt=tree[root<<1].cnt+tree[root<<1|1].cnt; } void add(int root,int l,int r,int x,int y,int z){ if ((x<=l)&&(y>=r)){ tree[root].min+=z; tree[root].mark+=z; if (tree[root].min<=0) updata(root,l,r); return; } pushdown(root,l,r); int mid=(l+r)>>1; if (x<=mid) add(root<<1,l,mid,x,y,z); if (y>mid) add(root<<1|1,mid+1,r,x,y,z); tree[root].min=min(tree[root<<1].min,tree[root<<1|1].min); tree[root].cnt=tree[root<<1].cnt+tree[root<<1|1].cnt; } int count(int root,int l,int r,int x,int y){ if ((x<=l)&&(y>=r)) return tree[root].cnt; int ans=0; int mid=(l+r)>>1; if (x<=mid) ans+=count(root<<1,l,mid,x,y); if (y>mid) ans+=count(root<<1|1,mid+1,r,x,y); return ans; } int main(){ scanf("%d%d",&n,&m); for (int i=1;i<=n;i++) scanf("%d",&voi[i]); build(1,1,n); while (m--){ scanf("%s",str); if (str[0]=='c'){ scanf("%d%d",&x,&y); printf("%d\n",count(1,1,n,x,y)); } else{ scanf("%d%d%d",&x,&y,&z); add(1,1,n,x,y,-z); } } return 0; }
神奇的代码
(cin只读入字符串还是巨慢QAQ改成scanf瞬间从3000ms+变成300ms+)
相关文章推荐
- JZOJ.5288【NOIP2017模拟8.17】球场大佬
- 【jzoj5289】【NOIP2017提高组A组模拟8.17】【偷笑】【数据结构】
- 【NOIP2017提高组A组模拟8.17】行程的交集
- 【NOIP2017提高A组模拟9.5】NYG的背包
- 【NOIP2017提高A组模拟9.14】生命之树 (dsu on tree+trie)
- NOIP2017金秋冲刺训练营杯联赛模拟大奖赛第二轮Day1
- NOIP2017金秋冲刺训练营杯联赛模拟大奖赛第一轮Day2题解
- NOIP2017提高A组模拟10.6】Biology
- NOIP2017赛前模拟 字符串(AC自动机)
- NOIP2017赛前模拟 Table(双向链表)
- JZOJ 4919.【NOIP2017提高组模拟12.10】神炎皇
- 【NOIP2017提高组模拟6.27】C
- JZOJ.5257【NOIP2017模拟8.11】小X的佛光
- 【NOIP2017提高A组模拟8.22】世界线
- JZOJ.5230【NOIP2017模拟8.5】队伍统计
- JZOJ.4709【NOIP2016提高A组模拟8.17】Matrix
- 【NOIP2016提高A组模拟8.17】(雅礼联考day1)总结
- 区间【NOIP2017提高A组模拟9.16】
- NOIP2017赛前模拟 Graph (2017.10.24)