您的位置:首页 > 其它

[Codevs] 4919 线段树练习4

2017-09-14 16:11 260 查看

4919 线段树练习4

 时间限制: 1 s  空间限制: 128000 KB  题目等级 : 黄金 Gold     题目描述 Description

给你N个数,有两种操作

1:给区间[a,b]内的所有数都增加X

2:询问区间[a,b]能被7整除的个数

  输入描述 Input Description

第一行一个正整数n,接下来n行n个整数,再接下来一个正整数Q,表示操作的个数. 接下来Q行每行若干个整数。如果第一个数是add,后接3个正整数a,b,X,表示在区间[a,b]内每个数增加X,如果是count,表示统计区间[a,b]能被7整除的个数

  输出描述 Output Description

对于每个询问输出一行一个答案

  样例输入 Sample Input   
3 
2 3 4
6
count 1 3
count 1 2
add 1 3 2
count 1 3
add 1 3 3
count 1 3

 

样例输出 Sample Output

0

0

0

1

  数据范围及提示 Data Size & Hint

10%:1<N<=10,1<Q<=10

30%:1<N<=10000,1<Q<=10000

100%:1<N<=100000,1<Q<=100000

 

分析 Analysis

分块!

相比线段树分块真的写起来很方便啊qwq

每个块保存块内关于 7 的剩余系的元素数量

(就是%7以后 0~6 的数量啦)

关键是add 操作,真恶心

用以前线段树的那套修改方案,最多过3个点

看了看TJM的方案:

每次整块增值时拉低bdd(负责保存历经修改以后整除 7 的数字到底是哪一个)

查询时计数 mod[ block[ i ] ][ bdd[ i ] ]

 

代码 Code 

#include<cstdio>
#include<iostream>
#include<cmath>
#define maxn 1000000
using namespace std;

char str[maxn/100];
int block[maxn],mod[maxn][10],size,arr[maxn],add[maxn],bdd[maxn],n,m;

void modify(){
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
a--,b--,c %= 7;
if(!c) return;

if(block[a] == block[b]){
for(int i = a;i <= b;i++){
mod[block[i]][arr[i]]--;
arr[i] = (arr[i]+c)%7;
mod[block[i]][arr[i]]++;
}
}else{

for(int i = a;i <= block[a]*size-1;i++)
mod[block[i]][arr[i]]--,
arr[i] = (arr[i]+c)%7,
mod[block[i]][arr[i]]++;
for(int i = (block[b]-1)*size;i <= b;i++)
mod[block[i]][arr[i]]--,
arr[i] = (arr[i]+c)%7,
mod[block[i]][arr[i]]++;
for(int i = block[a]+1;i < block[b];i++)
add[i] = (add[i]+c)%7,
bdd[i] = (bdd[i]-c+7)%7;

}
}

void count(){
int a,b;
scanf("%d%d",&a,&b);
a--,b--;
int ans = 0;

if(block[a] == block[b]){
for(int i = a;i <= b;i++)
ans += ((arr[i]+add[block[i]])%7)?0:1;
}else{

for(int i = a;i <= block[a]*size-1;i++)
ans += ((arr[i]+add[block[i]])%7)?0:1;
for(int i = (block[b]-1)*size;i <= b;i++)
ans += ((arr[i]+add[block[i]])%7)?0:1;
for(int i = block[a]+1;i < block[b];i++)
ans += mod[i][bdd[i]];

}

printf("%d\n",ans);
}

void show(){
for(int i = 0;i < n;i++){
printf("%d ",arr[i]+add[block[i]]);
}cout << endl;
}

int main(){
scanf("%d",&n);
size = (int)sqrt(n)+1;
for(int i = 0;i < n;i++) block[i] = i/size+1;
//    for(int i = 0;i < n;i++) printf("#%d: block %d\n",i,block[i]);
for(int i = 0;i < n;i++){
scanf("%d",&arr[i]);
arr[i] %= 7;
mod[block[i]][arr[i]]++;
}
//    show();
scanf("%d",&m);
for(int i = 0;i < m;i++){
scanf("%s",str);
if(str[0] == 'a') modify();
else count();
//        show();
}

return 0;
}
我不想退役qwq

 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: