数列分块入门 1
1.题意:
区间加法,单点查值
2.题解:
死活不知道开始为什么超时
3.ac代码:
#include <bits/stdc++.h>
#include <math.h>
using namespace std;
typedef long long ll;
const int N = 50000 + 10;
int a[N];
int n, m;
int st[N], ed[N], sz[N], sum[N], bel[N], mark[N];
inline void init(int n) { //分块
int sq = sqrt(n);
for (int i = 1; i <= sq; i++) {
st[i] = sq * (i - 1) + 1;
ed[i] = sq * i;
sz[i] = ed[i] - st[i] + 1;
}
ed[sq] = n;
sz[sq] = ed[sq] - st[sq] + 1;
for (int i = 1; i <= sq; i++) {
for (int j = st[i]; j <= ed[i]; j++) {
bel[j] = i;
// sum[i]+=a[j];
}
}
}
inline void change(int l, int r, int d) { //区间修改,加上一个数
if (bel[l] == bel[r]) {
for (int i = l; i <= r; i++) {
a[i] += d;
// sum[bel[i]]+=d;
}
} else {
for (int i = l; i <= ed[bel[l]]; i++)
a[i] += d;
// sum[bel[l]]+=d*(ed[bel[l]]-l+1);
for (int i = st[bel[r]]; i <= r; i++)
a[i] += d;
//sum[bel[r]]+=d*(r-st[bel[r]]+1);
for (int i = bel[l] + 1; i < bel[r]; i++)
mark[i] += d;
}
}
//ll query(int l,int r){//区间查询
// ll ans=0;
// if(bel[l]==bel[r]){
// for(int i=l;i<=r;i++) ans+=a[i];
// ans+=mark[bel[l]]*(r-l+1);
// }else{
// for(int i=l;i<=ed[bel[l]];i++) ans+=a[i];
// ans+=mark[bel[l]]*(ed[bel[l]]-l+1);
// for(int i=st[bel[r]];i<=r;i++) ans+=a[i];
// ans+=mark[bel[r]]*(r-st[bel[r]]+1);
// for(int i=bel[l]+1;i<bel[r];i++) ans+=sum[i]+mark[i]*sz[i];
//
// }
//}
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; i++)
scanf("%d", &a[i]);
int l, r, op;
int c;
init(n);
for (int i = 1; i <= n; i++) {
scanf("%d%d%d%d", &op, &l, &r, &c);
if (op == 0) {
change(l, r, c);
} else {
printf("%d\n", a[r] + mark[bel[r]]);
}
}
}
数列分块入门 2
1.题意:
区间加法,询问区间内小于某个值 x的元素个数。
2.题解:
!!!快哭了啊啊啊啊啊啊,我终于知道我错哪了,卡了我快俩小时md
3.ac代码:
#include <bits/stdc++.h>
#include <math.h>
using namespace std;
typedef long long ll;
const int N = 50000 + 10;
int a[N];
int n, m;
int st[N], ed[N], sz[N], sum[N], bel[N], mark[N];
vector<int> v[N];
inline void init(int n) { //分块
int sq = sqrt(n);
for (int i = 1; i <= sq; i++) {
st[i] = sq * (i - 1) + 1;
ed[i] = sq * i;
sz[i] = ed[i] - st[i] + 1;
}
ed[sq] = n;
sz[sq] = ed[sq] - st[sq] + 1;
for (int i = 1; i <= sq; i++) {
for (int j = st[i]; j <= ed[i]; j++) {
bel[j] = i;
v[i].push_back(a[j]);
sum[i]+=a[j];
}
sort(v[i].begin(),v[i].end());
}
}
void reset(int i){
for(int j=0;j<=sz[i];j++){
v[i][j]=a[st[i]+j];
}
sort(v[i].begin(),v[i].end());
}
inline void change(int l, int r, int d) { //区间修改,加上一个数
if (bel[l] == bel[r]) {
for (int i = l; i <= r; i++) {
a[i] += d;
}
reset(bel[l]);
} else {
for (int i = l; i <= ed[bel[l]]; i++)
a[i] += d;
reset(bel[l]);
for (int i = st[bel[r]]; i <= r; i++)
a[i] += d;
reset(bel[r]);
for (int i = bel[l] + 1; i < bel[r]; i++)
mark[i] += d;
}
}
int query(int l,int r,int c){//区间查询,小于c的个数
int ans=0;
if(bel[l]==bel[r]){
for(int i=l;i<=r;i++){
if(a[i]+mark[bel[i]]<c*c) ans++;
}
}else{
for(int i=l;i<=ed[bel[l]];i++){
if(a[i]+mark[bel[l]]<c*c) ans++;
}
for(int i=st[bel[r]];i<=r;i++){
if(a[i]+mark[bel[r]]<c*c) ans++;
}
for(int i=bel[l]+1;i<bel[r];i++){
ans+=lower_bound(v[i].begin(), v[i].end(),c*c-mark[i])-v[i].begin();//!!!mark【i】!!不是mark【bel【i】】
}
}
return ans;
}
int main() {
cin>>n;
for (int i = 1; i <= n; i++)
cin>>a[i];
int l, r, op;
ll c;
init(n);
for (int i = 1; i <= n; i++) {
cin>>op>>l>>r>>c;
if (op == 0) {
change(l, r, c);
} else {
cout<<query(l,r,c)<<endl;
}
}
}
数列分块入门 3
1.题意:
区间加法+询区间内比x小的最大元素
2.题解:
在 [first, last) 区域内查找
- lower_bound(,x) 第一个>=x
int a[5] = { 1,2,3,4,5 };
//从 a 数组中找到第一个不小于 3 的元素
int *p = lower_bound(a, a + 5, 3);
*p=3
- upper bound(,x) 第一个>x
int a[5] = { 1,2,3,4,5 };
//从 a 数组中找到第一个大于 3 的元素
int *p = upper_bound(a, a + 5, 3);
*p = 4
3.ac代码:
#include <bits/stdc++.h>
#include <math.h>
using namespace std;
typedef long long ll;
const int N =1e6 + 10;
int a[N];
int n, m;
int st[N], ed[N], sz[N], sum[N], bel[N], mark[N];
vector<int> v[N];
inline void init(int n) { //分块
int sq = sqrt(n);
for (int i = 1; i <= sq; i++) {
st[i] = sq * (i - 1) + 1;
ed[i] = sq * i;
sz[i] = ed[i] - st[i] + 1;
}
ed[sq] = n;
sz[sq] = ed[sq] - st[sq] + 1;
for (int i = 1; i <= sq; i++) {
for (int j = st[i]; j <= ed[i]; j++) {
bel[j] = i;
v[i].push_back(a[j]);
sum[i]+=a[j];
}
sort(v[i].begin(),v[i].end());
}
}
void reset(int i){
for(int j=0;j<=sz[i];j++){
v[i][j]=a[st[i]+j];
}
sort(v[i].begin(),v[i].end());
}
inline void change(int l, int r, int d) { //区间修改,加上一个数
if (bel[l] == bel[r]) {
for (int i = l; i <= r; i++) {
a[i] += d;
}
reset(bel[l]);
} else {
for (int i = l; i <= ed[bel[l]]; i++)
a[i] += d;
reset(bel[l]);
for (int i = st[bel[r]]; i <= r; i++)
a[i] += d;
reset(bel[r]);
for (int i = bel[l] + 1; i < bel[r]; i++)
mark[i] += d;
}
}
int query1(int l,int r,int c){//区间查询,小于c的个数
int ans=0;
if(bel[l]==bel[r]){
for(int i=l;i<=r;i++){
if(a[i]+mark[bel[i]]<c*c) ans++;
}
}else{
for(int i=l;i<=ed[bel[l]];i++){
if(a[i]+mark[bel[l]]<c*c) ans++;
}
for(int i=st[bel[r]];i<=r;i++){
if(a[i]+mark[bel[r]]<c*c) ans++;
}
for(int i=bel[l]+1;i<bel[r];i++){
ans+=lower_bound(v[i].begin(), v[i].end(),c*c-mark[i])-v[i].begin();
}
}
return ans;
}
int query2(int l,int r,int c){//查询区间内比x小的最大元素
int ans=-1;
if(bel[l]==bel[r]){
for(int i=l;i<=r;i++){
if(a[i]+mark[bel[i]]<c) ans=max(ans,a[i]+mark[bel[i]]);
}
}else{
for(int i=l;i<=ed[bel[l]];i++){
if(a[i]+mark[bel[l]]<c) ans=max(ans,a[i]+mark[bel[l]]);
}
for(int i=st[bel[r]];i<=r;i++){
if(a[i]+mark[bel[r]]<c) ans=max(ans,a[i]+mark[bel[r]]);
}
for(int i=bel[l]+1;i<bel[r];i++){
int t=lower_bound(v[i].begin(), v[i].end(),c-mark[i])-v[i].begin();
if(t){
ans=max(ans,v[i][t-1]+mark[i]);
}
}
}
return ans;
}
int main() {
cin>>n;
for (int i = 1; i <= n; i++)
cin>>a[i];
int l, r, op;
ll c;
init(n);
for (int i = 1; i <= n; i++) {
cin>>op>>l>>r>>c;
if (op == 0) {
change(l, r, c);
} else {
cout<<query2(l,r,c)<<endl;
}
}
}
数列分块入门 4
1.题意:
区间加法,区间求和
2.题解:
散块暴力,整块求和,求整块和时要把标记乘上块大小,同时记得i表示块th
3.ac代码:
#include <bits/stdc++.h>
#include <math.h>
using namespace std;
typedef long long ll;
const int N =1e6 + 10;
int a[N];
int n, m;
int st[N], ed[N], sz[N], sum[N], bel[N], mark[N];
vector<int> v[N];
inline void init(int n) { //分块
int sq = sqrt(n);
for (int i = 1; i <= sq; i++) {
st[i] = sq * (i - 1) + 1;
ed[i] = sq * i;
sz[i] = ed[i] - st[i] + 1;
}
ed[sq] = n;
sz[sq] = ed[sq] - st[sq] + 1;
for (int i = 1; i <= sq; i++) {
for (int j = st[i]; j <= ed[i]; j++) {
bel[j] = i;
v[i].push_back(a[j]);
sum[i]+=a[j];
}
sort(v[i].begin(),v[i].end());
}
}
void reset(int i){
for(int j=0;j<=sz[i];j++){
v[i][j]=a[st[i]+j];
}
sort(v[i].begin(),v[i].end());
}
inline void change(int l, int r, int d) { //区间修改,加上一个数
if (bel[l] == bel[r]) {
for (int i = l; i <= r; i++) {
a[i] += d;
sum[bel[i]]+=d;
}
reset(bel[l]);
} else {
for (int i = l; i <= ed[bel[l]]; i++)
a[i] += d,sum[bel[i]]+=d;
reset(bel[l]);
for (int i = st[bel[r]]; i <= r; i++)
a[i] += d,sum[bel[i]]+=d;
reset(bel[r]);
for (int i = bel[l] + 1; i < bel[r]; i++)
mark[i] += d;
}
}
int query1(int l,int r,int c){//区间查询,小于c的个数
int ans=0;
if(bel[l]==bel[r]){
for(int i=l;i<=r;i++){
if(a[i]+mark[bel[i]]<c*c) ans++;
}
}else{
for(int i=l;i<=ed[bel[l]];i++){
if(a[i]+mark[bel[l]]<c*c) ans++;
}
for(int i=st[bel[r]];i<=r;i++){
if(a[i]+mark[bel[r]]<c*c) ans++;
}
for(int i=bel[l]+1;i<bel[r];i++){
ans+=lower_bound(v[i].begin(), v[i].end(),c*c-mark[i])-v[i].begin();
}
}
return ans;
}
int query2(int l,int r,int c){//查询区间内比x小的最大元素
int ans=-1;
if(bel[l]==bel[r]){
for(int i=l;i<=r;i++){
if(a[i]+mark[bel[i]]<c) ans=max(ans,a[i]+mark[bel[i]]);
}
}else{
for(int i=l;i<=ed[bel[l]];i++){
if(a[i]+mark[bel[l]]<c) ans=max(ans,a[i]+mark[bel[l]]);
}
for(int i=st[bel[r]];i<=r;i++){
if(a[i]+mark[bel[r]]<c) ans=max(ans,a[i]+mark[bel[r]]);
}
for(int i=bel[l]+1;i<bel[r];i++){
int t=lower_bound(v[i].begin(), v[i].end(),c-mark[i])-v[i].begin();
if(t){
ans=max(ans,v[i][t-1]+mark[i]);
}
}
}
return ans;
}
int query(int l,int r,int c){//区间和mod(c+1)
int ans=0;
if(bel[l]==bel[r]){
for(int i=l;i<=r;i++){
ans=(a[i]+mark[bel[i]]+ans)%(c+1);
}
}else{
for(int i=l;i<=ed[bel[l]];i++){
ans=(a[i]+mark[bel[i]]+ans)%(c+1);
}
for(int i=st[bel[r]];i<=r;i++){
ans=(a[i]+mark[bel[i]]+ans)%(c+1);
}
for(int i=bel[l]+1;i<bel[r];i++){
ans=(sum[i]+(ll)sz[i]*mark[i]%(c+1)+ans)%(c+1);
}
}
return ans;
}
int main() {
cin>>n;
for (int i = 1; i <= n; i++)
cin>>a[i];
int l, r, op;
ll c;
init(n);
for (int i = 1; i <= n; i++) {
cin>>op>>l>>r>>c;
if (op == 0) {
change(l, r, c);
} else {
cout<<query(l,r,c)<<endl;
}
}
}
数列分块入门 5
1.题意:
区间开方,区间求和
2.题解:
当数字开方到1/0后,再开方数字不变,所以对整块都是0/1的块做标记,即下次不用再处理了,
开方时对零散块暴力,对整块采用标记处理
query依然对零散块暴力求解,对整块直接返回sum
3.ac代码:
#include <bits/stdc++.h>
#include <math.h>
using namespace std;
typedef long long ll;
const int N =1e6 + 10;
int a[N];
int n, m;
int st[N], ed[N], sz[N], sum[N], bel[N], mark[N];
int flag[N];
vector<int> v[N];
inline void init(int n) { //分块
int sq = sqrt(n);
for (int i = 1; i <= sq; i++) {
st[i] = sq * (i - 1) + 1;
ed[i] = sq * i;
sz[i] = ed[i] - st[i] + 1;
}
ed[sq] = n;
sz[sq] = ed[sq] - st[sq] + 1;
for (int i = 1; i <= sq; i++) {
for (int j = st[i]; j <= ed[i]; j++) {
bel[j] = i;
v[i].push_back(a[j]);
sum[i]+=a[j];
}
sort(v[i].begin(),v[i].end());
}
}
void reset(int i){
for(int j=0;j<=sz[i];j++){
v[i][j]=a[st[i]+j];
}
sort(v[i].begin(),v[i].end());
}
inline void change(int l, int r, int d) { //区间修改,加上一个数
if (bel[l] == bel[r]) {
for (int i = l; i <= r; i++) {
a[i] += d;
sum[bel[i]]+=d;
}
reset(bel[l]);
} else {
for (int i = l; i <= ed[bel[l]]; i++)
a[i] += d,sum[bel[i]]+=d;
reset(bel[l]);
for (int i = st[bel[r]]; i <= r; i++)
a[i] += d,sum[bel[i]]+=d;
reset(bel[r]);
for (int i = bel[l] + 1; i < bel[r]; i++)
mark[i] += d;
}
}
int query(int l,int r,int c){//区间和mod(c+1)
int ans=0;
if(bel[l]==bel[r]){
for(int i=l;i<=r;i++){
ans=(a[i]+mark[bel[i]]+ans)%(c+1);
}
}else{
for(int i=l;i<=ed[bel[l]];i++){
ans=(a[i]+mark[bel[i]]+ans)%(c+1);
}
for(int i=st[bel[r]];i<=r;i++){
ans=(a[i]+mark[bel[i]]+ans)%(c+1);
}
for(int i=bel[l]+1;i<bel[r];i++){
ans=(sum[i]+(ll)sz[i]*mark[i]%(c+1)+ans)%(c+1);
}
}
return ans;
}
int query1(int l,int r,int c){//区间查询,小于c的个数
int ans=0;
if(bel[l]==bel[r]){
for(int i=l;i<=r;i++){
if(a[i]+mark[bel[i]]<c*c) ans++;
}
}else{
for(int i=l;i<=ed[bel[l]];i++){
if(a[i]+mark[bel[l]]<c*c) ans++;
}
for(int i=st[bel[r]];i<=r;i++){
if(a[i]+mark[bel[r]]<c*c) ans++;
}
for(int i=bel[l]+1;i<bel[r];i++){
ans+=lower_bound(v[i].begin(), v[i].end(),c*c-mark[i])-v[i].begin();
}
}
return ans;
}
int query2(int l,int r,int c){//查询区间内比x小的最大元素
int ans=-1;
if(bel[l]==bel[r]){
for(int i=l;i<=r;i++){
if(a[i]+mark[bel[i]]<c) ans=max(ans,a[i]+mark[bel[i]]);
}
}else{
for(int i=l;i<=ed[bel[l]];i++){
if(a[i]+mark[bel[l]]<c) ans=max(ans,a[i]+mark[bel[l]]);
}
for(int i=st[bel[r]];i<=r;i++){
if(a[i]+mark[bel[r]]<c) ans=max(ans,a[i]+mark[bel[r]]);
}
for(int i=bel[l]+1;i<bel[r];i++){
int t=lower_bound(v[i].begin(), v[i].end(),c-mark[i])-v[i].begin();
if(t){
ans=max(ans,v[i][t-1]+mark[i]);
}
}
}
return ans;
}
int query3(int l,int r){//区间开方的求和
int ans=0;
if(bel[l]==bel[r]){
for(int i=l;i<=r;i++){
ans+=a[i]+mark[bel[i]];
}
}else{
for(int i=l;i<=ed[bel[l]];i++){
ans+=a[i]+mark[bel[i]];
}
for(int i=st[bel[r]];i<=r;i++){
ans+=a[i]+mark[bel[i]];
}
for(int i=bel[l]+1;i<bel[r];i++){
ans+=sum[i];
}
}
return ans;
}
void solve_sqrt(int x){//对整块开放后的区间处理sum
if(flag[x]) return;//flag!=0即整块不用处理
flag[x]=1;
sum[x]=0;
for(int i=st[x];i<=ed[x];i++){
a[i]=sqrt(a[i]);
sum[x]+=a[i];
if(a[i]>1) flag[x]=0;
}
}
void changeSqrt(int l,int r){//区间开方
if (bel[l] == bel[r]) {
for (int i = l; i <= r; i++) {
sum[bel[i]]-=a[i];
a[i] =sqrt(a[i]);
sum[bel[i]]+=a[i];
}
} else {
for (int i = l; i <= ed[bel[l]]; i++){
sum[bel[i]]-=a[i];
a[i] =sqrt(a[i]);
sum[bel[i]]+=a[i];
}
for (int i = st[bel[r]]; i <= r; i++){
sum[bel[i]]-=a[i];
a[i] =sqrt(a[i]);
sum[bel[i]]+=a[i];
}
for (int i = bel[l] + 1; i < bel[r]; i++){
solve_sqrt(i);
}
}
}
int main() {
cin>>n;
for (int i = 1; i <= n; i++)
cin>>a[i];
int l, r, op;
ll c;
init(n);
for (int i = 1; i <= n; i++) {
cin>>op>>l>>r>>c;
if (op == 0) {
changeSqrt(l, r);
} else {
cout<<query3(l,r)<<endl;
}
}
}
数列分块入门 6
1.题意:
单点插入,单点询问,数据随机生成
2.题解:
关键是rebuild,当增加的数值达到一个块的大小时,就重新分块
开始一直wa是因为,写之前的题里头,把v排序了
3.ac代码:
#include <bits/stdc++.h>
#include <math.h>
using namespace std;
typedef long long ll;
const int N =1e6 + 10;
int a[N];
int n, m;
int sq;
int st[N], ed[N], sz[N], sum[N], bel[N], mark[N];
int flag[N];
vector<int> v[N];
inline void init(int n) { //分块
sq = sqrt(n);
for (int i = 1; i <= sq; i++) {
st[i] = sq * (i - 1) + 1;
ed[i] = sq * i;
sz[i] = ed[i] - st[i] + 1;
}
ed[sq] = n;
sz[sq] = ed[sq] - st[sq] + 1;
for (int i = 1; i <= sq; i++) {
for (int j = st[i]; j <= ed[i]; j++) {
bel[j] = i;
v[i].push_back(a[j]);
sum[i]+=a[j];
}
// sort(v[i].begin(),v[i].end());
}
}
void reset(int i){
for(int j=0;j<=sz[i];j++){
v[i][j]=a[st[i]+j];
}
sort(v[i].begin(),v[i].end());
}
void rebuild(){//重新分块
int k=0;
for(int i=1;i<=sq;i++){
for(int j=0;j<v[i].size();j++){
a[++k]=v[i][j];
}
v[i].clear();
}
sq=sqrt(k);
for(int i=1;i<=k;i++){
v[(i-1)/sq+1].push_back(a[i]);
}
}
inline void change(int l, int r, int d) { //区间修改,加上一个数
if (bel[l] == bel[r]) {
for (int i = l; i <= r; i++) {
a[i] += d;
sum[bel[i]]+=d;
}
reset(bel[l]);
} else {
for (int i = l; i <= ed[bel[l]]; i++)
a[i] += d,sum[bel[i]]+=d;
reset(bel[l]);
for (int i = st[bel[r]]; i <= r; i++)
a[i] += d,sum[bel[i]]+=d;
reset(bel[r]);
for (int i = bel[l] + 1; i < bel[r]; i++)
mark[i] += d;
}
}
pair<int,int> query4(int x){
int i=1;
while(x>v[i].size()){
x-=v[i].size();
i++;
}
return make_pair(i,x-1);
}
void insert(int l,int r){//单点插入,在第l个数字前插入r
auto t=query4(l);
v[t.first].insert(v[t.first].begin()+t.second, r);
}
int query(int l,int r,int c){//区间和mod(c+1)
int ans=0;
if(bel[l]==bel[r]){
for(int i=l;i<=r;i++){
ans=(a[i]+mark[bel[i]]+ans)%(c+1);
}
}else{
for(int i=l;i<=ed[bel[l]];i++){
ans=(a[i]+mark[bel[i]]+ans)%(c+1);
}
for(int i=st[bel[r]];i<=r;i++){
ans=(a[i]+mark[bel[i]]+ans)%(c+1);
}
for(int i=bel[l]+1;i<bel[r];i++){
ans=(sum[i]+(ll)sz[i]*mark[i]%(c+1)+ans)%(c+1);
}
}
return ans;
}
int query1(int l,int r,int c){//区间查询,小于c的个数
int ans=0;
if(bel[l]==bel[r]){
for(int i=l;i<=r;i++){
if(a[i]+mark[bel[i]]<c*c) ans++;
}
}else{
for(int i=l;i<=ed[bel[l]];i++){
if(a[i]+mark[bel[l]]<c*c) ans++;
}
for(int i=st[bel[r]];i<=r;i++){
if(a[i]+mark[bel[r]]<c*c) ans++;
}
for(int i=bel[l]+1;i<bel[r];i++){
ans+=lower_bound(v[i].begin(), v[i].end(),c*c-mark[i])-v[i].begin();
}
}
return ans;
}
int query2(int l,int r,int c){//查询区间内比x小的最大元素
int ans=-1;
if(bel[l]==bel[r]){
for(int i=l;i<=r;i++){
if(a[i]+mark[bel[i]]<c) ans=max(ans,a[i]+mark[bel[i]]);
}
}else{
for(int i=l;i<=ed[bel[l]];i++){
if(a[i]+mark[bel[l]]<c) ans=max(ans,a[i]+mark[bel[l]]);
}
for(int i=st[bel[r]];i<=r;i++){
if(a[i]+mark[bel[r]]<c) ans=max(ans,a[i]+mark[bel[r]]);
}
for(int i=bel[l]+1;i<bel[r];i++){
int t=lower_bound(v[i].begin(), v[i].end(),c-mark[i])-v[i].begin();
if(t){
ans=max(ans,v[i][t-1]+mark[i]);
}
}
}
return ans;
}
int query3(int l,int r){//区间开方的求和
int ans=0;
if(bel[l]==bel[r]){
for(int i=l;i<=r;i++){
ans+=a[i]+mark[bel[i]];
}
}else{
for(int i=l;i<=ed[bel[l]];i++){
ans+=a[i]+mark[bel[i]];
}
for(int i=st[bel[r]];i<=r;i++){
ans+=a[i]+mark[bel[i]];
}
for(int i=bel[l]+1;i<bel[r];i++){
ans+=sum[i];
}
}
return ans;
}
void solve_sqrt(int x){//对整块开放后的区间处理sum
if(flag[x]) return;//flag!=0即整块不用处理
flag[x]=1;
sum[x]=0;
for(int i=st[x];i<=ed[x];i++){
a[i]=sqrt(a[i]);
sum[x]+=a[i];
if(a[i]>1) flag[x]=0;
}
}
void changeSqrt(int l,int r){//区间开方
if (bel[l] == bel[r]) {
for (int i = l; i <= r; i++) {
sum[bel[i]]-=a[i];
a[i] =sqrt(a[i]);
sum[bel[i]]+=a[i];
}
} else {
for (int i = l; i <= ed[bel[l]]; i++){
sum[bel[i]]-=a[i];
a[i] =sqrt(a[i]);
sum[bel[i]]+=a[i];
}
for (int i = st[bel[r]]; i <= r; i++){
sum[bel[i]]-=a[i];
a[i] =sqrt(a[i]);
sum[bel[i]]+=a[i];
}
for (int i = bel[l] + 1; i < bel[r]; i++){
solve_sqrt(i);
}
}
}
int main() {
cin>>n;
for (int i = 1; i <= n; i++)
cin>>a[i];
int l, r, op;
ll c;
sq=sqrt(n);
init(n);
int cnt=0;
for (int i = 1; i <= n; i++) {
cin>>op>>l>>r>>c;
if (op == 0) {
insert(l,r);cnt++;
} else {
auto t=query4(r);
cout<<v[t.first][t.second]<<endl;
}
if(cnt==sq){
rebuild();
cnt=0;
}
}
}
数列分块入门 7
1.题意:
区间乘法,区间加法,单点询问
2.题解:
本质上和区间加法差不多,更新零散块后再暴力,对整块做整块标记处理。
3.ac代码:
#include <bits/stdc++.h>
#include <math.h>
using namespace std;
typedef long long ll;
const int N = 1e6 + 10;
const int mod = 10007;
ll a[N];
int n, m;
int sq;
int st[N], ed[N], sz[N], sum[N], bel[N];
int flag[N];
ll multi[N], mark[N];
vector<int> v[N];
inline void init(int n) { //分块
sq = sqrt(n);
for (int i = 1; i <= sq; i++) {
st[i] = sq * (i - 1) + 1;
ed[i] = sq * i;
sz[i] = ed[i] - st[i] + 1;
}
ed[sq] = n;
sz[sq] = ed[sq] - st[sq] + 1;
for (int i = 1; i <= sq; i++) {
multi[i] = 1;
for (int j = st[i]; j <= ed[i]; j++) {
bel[j] = i;
v[i].push_back(a[j]);
sum[i] += a[j];
}
// sort(v[i].begin(),v[i].end());
}
}
void reset(int i) { //排序v
for (int j = 0; j <= sz[i]; j++) {
v[i][j] = a[st[i] + j];
}
sort(v[i].begin(), v[i].end());
}
void rebuild() { //重新分块
int k = 0;
for (int i = 1; i <= sq; i++) {
for (int j = 0; j < v[i].size(); j++) {
a[++k] = v[i][j];
}
v[i].clear();
}
sq = sqrt(k);
for (int i = 1; i <= k; i++) {
v[(i - 1) / sq + 1].push_back(a[i]);
}
}
inline void change(int l, int r, int d) { //区间修改,加上一个数
if (bel[l] == bel[r]) {
for (int i = l; i <= r; i++) {
a[i] += d;
sum[bel[i]] += d;
}
reset(bel[l]);
} else {
for (int i = l; i <= ed[bel[l]]; i++)
a[i] += d, sum[bel[i]] += d;
reset(bel[l]);
for (int i = st[bel[r]]; i <= r; i++)
a[i] += d, sum[bel[i]] += d;
reset(bel[r]);
for (int i = bel[l] + 1; i < bel[r]; i++)
mark[i] += d;
}
}
pair<int, int> query4(int x) {
int i = 1;
while (x > v[i].size()) {
x -= v[i].size();
i++;
}
return make_pair(i, x - 1);
}
//void insert(int l, int r) { //单点插入,在第l个数字前插入r
// auto t = query4(l);
// v[t.first].insert(v[t.first].begin() + t.second, r);
//
//}
int query(int l, int r, int c) { //区间和mod(c+1)
int ans = 0;
if (bel[l] == bel[r]) {
for (int i = l; i <= r; i++) {
ans = (a[i] + mark[bel[i]] + ans) % (c + 1);
}
} else {
for (int i = l; i <= ed[bel[l]]; i++) {
ans = (a[i] + mark[bel[i]] + ans) % (c + 1);
}
for (int i = st[bel[r]]; i <= r; i++) {
ans = (a[i] + mark[bel[i]] + ans) % (c + 1);
}
for (int i = bel[l] + 1; i < bel[r]; i++) {
ans = (sum[i] + (ll)sz[i] * mark[i] % (c + 1) + ans) % (c + 1);
}
}
return ans;
}
int query1(int l, int r, int c) { //区间查询,小于c的个数
int ans = 0;
if (bel[l] == bel[r]) {
for (int i = l; i <= r; i++) {
if (a[i] + mark[bel[i]] < c * c)
ans++;
}
} else {
for (int i = l; i <= ed[bel[l]]; i++) {
if (a[i] + mark[bel[l]] < c * c)
ans++;
}
for (int i = st[bel[r]]; i <= r; i++) {
if (a[i] + mark[bel[r]] < c * c)
ans++;
}
for (int i = bel[l] + 1; i < bel[r]; i++) {
ans += lower_bound(v[i].begin(), v[i].end(), c * c - mark[i]) - v[i].begin();
}
}
return ans;
}
int query3(int l, int r) { //区间开方的求和
int ans = 0;
if (bel[l] == bel[r]) {
for (int i = l; i <= r; i++) {
ans += a[i] + mark[bel[i]];
}
} else {
for (int i = l; i <= ed[bel[l]]; i++) {
ans += a[i] + mark[bel[i]];
}
for (int i = st[bel[r]]; i <= r; i++) {
ans += a[i] + mark[bel[i]];
}
for (int i = bel[l] + 1; i < bel[r]; i++) {
ans += sum[i];
}
}
return ans;
}
void solve_sqrt(int x) { //对整块开放后的区间处理sum
if (flag[x])
return;//flag!=0即整块不用处理
flag[x] = 1;
sum[x] = 0;
for (int i = st[x]; i <= ed[x]; i++) {
a[i] = sqrt(a[i]);
sum[x] += a[i];
if (a[i] > 1)
flag[x] = 0;
}
}
void changeSqrt(int l, int r) { //区间开方
if (bel[l] == bel[r]) {
for (int i = l; i <= r; i++) {
sum[bel[i]] -= a[i];
a[i] = sqrt(a[i]);
sum[bel[i]] += a[i];
}
} else {
for (int i = l; i <= ed[bel[l]]; i++) {
sum[bel[i]] -= a[i];
a[i] = sqrt(a[i]);
sum[bel[i]] += a[i];
}
for (int i = st[bel[r]]; i <= r; i++) {
sum[bel[i]] -= a[i];
a[i] = sqrt(a[i]);
sum[bel[i]] += a[i];
}
for (int i = bel[l] + 1; i < bel[r]; i++) {
solve_sqrt(i);
}
}
}
void update(int l) {
for (int i = st[l]; i <= ed[l]; i++) {
a[i] = (multi[l] * a[i]%mod + mark[l]) % mod;
}
multi[l] = 1;
mark[l] = 0;
}
void change(int op, int l, int r, int d) { //乘法,加法
update(bel[l]);
if (op == 0) {
if (bel[l] == bel[r]) {
for (int i = l; i <= r; i++) {
a[i]=(a[i]+d)%mod;
}
} else {
update(bel[r]);
for (int i = l; i <= ed[bel[l]]; i++)
a[i]=(a[i]+d)%mod;
for (int i = st[bel[r]]; i <= r; i++)
a[i]=(a[i]+d)%mod;
for (int i = bel[l] + 1; i < bel[r]; i++)
mark[i]=(mark[i]+d)%mod;
}
} else {
if (bel[l] == bel[r]) {
for (int i = l; i <= r; i++) {
a[i] = a[i] *d % mod;
}
} else {
update(bel[r]);
for (int i = l; i <= ed[bel[l]]; i++)
a[i] = a[i] *d % mod;
for (int i = st[bel[r]]; i <= r; i++)
a[i] = a[i] *d % mod;
for (int i = bel[l] + 1; i < bel[r]; i++)
multi[i]= d *multi[i] % mod,mark[i]=mark[i]*d%mod;//!!!切记乘法 对加法标记也要乘上去
}
}
}
int main() {
cin >> n;
for (int i = 1; i <= n; i++)
cin >> a[i];
int l, r, op;
ll c;
sq = sqrt(n);
init(n);
for (int i = 1; i <= n; i++) {
cin >> op >> l >> r >> c;
if (op == 2) {
cout << (multi[bel[r]]*a[r]%mod + mark[bel[r]]) % mod << endl;
} else {
change(op, l, r, c);
}
}
}
数列分块入门 8
1.题意:
操作涉及区间询问等于一个数 的元素,并将这个区间的所有元素改为 。
2.题解:
整块变化则将整块标记,跟前面的题类似
易错:1.传参传的是组号,不是区间短点,2.注意参数到底是谁
3.ac代码:
#include <bits/stdc++.h>
#include <math.h>
using namespace std;
typedef long long ll;
const int N = 2e5 + 10;
const int INF=0x3f3f3f3f;
ll a[N];
int n, m;
int sq;
int st[N], ed[N], sz[N], sum[N], bel[N];
int num[N];
ll multi[N], mark[N];
vector<int> v[N];
inline void init(int n) { //分块
sq = sqrt(n);
for (int i = 1; i <= sq; i++) {
st[i] = sq * (i - 1) + 1;
ed[i] = sq * i;
sz[i] = ed[i] - st[i] + 1;
}
ed[sq] = n;
sz[sq] = ed[sq] - st[sq] + 1;
for (int i = 1; i <= sq; i++) {
multi[i] = 1;
for (int j = st[i]; j <= ed[i]; j++) {
bel[j] = i;
v[i].push_back(a[j]);
sum[i] += a[j];
}
// sort(v[i].begin(),v[i].end());
}
}
void update1(int x){
if(num[x]==-1) return;
for(int i=st[x];i<=ed[x];i++){
a[i]=num[x];
}
num[x]=-1;
}
//void change(int op, int l, int r, int d) { //乘法,加法
int query4(int l,int r,int c){//查询区间中c的个数,并把区间所有数组改成c
int sum=0;
update1(bel[l]);
if(bel[l]==bel[r]){
for(int i=l;i<=r;i++){
if(a[i]==c) sum++;
else a[i]=c;
}
}else{
for(int i=l;i<=ed[bel[l]];i++){
if(a[i]==c) sum++;
else a[i]=c;
}
update1(bel[r]);
for(int i=st[bel[r]];i<=r;i++){
if(a[i]==c) sum++;
else a[i]=c;
}
for(int i=bel[l]+1;i<bel[r];i++){
if(num[i]==-1){
for(int j=st[i];j<=ed[i];j++){
if(a[j]==c) sum++;
else a[j]=c;
}
num[i]=c;
}else{
if(num[i]==c) sum+=sz[i];
num[i]=c;
}
}
}
return sum;
}
int main() {
cin >> n;
memset(num,-1,sizeof num);
for (int i = 1; i <= n; i++){
cin >> a[i];
}
int l, r, op;
ll c;
sq = sqrt(n);
init(n);
for (int i = 1; i <= n; i++) {
cin >> l >> r >> c;
cout<<query4(l,r,c)<<endl;
}
}
数列分块入门 9
1.题意:
离线的区间众数
2.题解:
!!!太好了啊啊啊啊啊啊啊啊啊啊啊啊,卡了我一下午,要不t要不wa要不re,终于终于!!
一开始错在,考虑了每个分块的众数,结果没有考虑几个块合成大块的众数
后来又是re,re,开始一直以为是数组越界,后来发现好像是数字太大了,不能z直接通过桶排计算,然后看别人代码学做了离散化
离散化后依旧re,然后把分块大小从√n变成了80
好了现在又是t了,不过好歹是80+,经过不断的改代码,我把map变成了普通的数组cnt,ookk终于过了!!,一个map让我超时了好久,我估计我用的pair也给我加了不少时,呜呜呜,我以后还老老实实用普通数组吧
总结下,这题基本思路:初始化求出不同块的众数+离散化+分块大小80+少用map等
历时几天的分块九题终于完了!!!撒花,感谢这位博主题解写的好!!
这题好像还能用莫队,回头试试
3.ac代码:
#include <bits/stdc++.h>
#include <math.h>
using namespace std;
typedef long long ll;
const int N = 1e6 + 10;
int f[5003][5003];
const int INF = 0x3f3f3f3f;
int a[N];
int n;
int sq;
int st[N], ed[N], sz[N], sum[N], bel[N];
int num[N];
ll multi[N], mark[N];
int cnt[N];
vector<int> v[N];
map<int, int> m;
int dis[N];
int count(int x, int l, int r) {
return upper_bound(v[x].begin(), v[x].end(), r) - lower_bound(v[x].begin(), v[x].end(), l);
}
inline void init(int n) { //分块
int val = 80;
sq = (n - 1) / val + 1;
for (int i = 1; i <= sq; i++) {
st[i] = val * (i - 1) + 1;
ed[i] = val * i;
sz[i] = ed[i] - st[i] + 1;
}
ed[sq] = n;
sz[sq] = ed[sq] - st[sq] + 1;
for (int i = 1; i <= sq; i++) {
for (int j = st[i]; j <= ed[i]; j++) {
bel[j] = i;
}
}
for (int i = 1; i <= sq; i++) {
int maxx = INF, maxn = 0;
memset(cnt, 0, sizeof cnt);
for (int k = i; k <= sq; k++) {
for (int j = st[k]; j <= ed[k]; j++) {
cnt[a[j]]++;
if (cnt[a[j]] > maxn) {
maxn = cnt[a[j]];
maxx = a[j];
} else if (cnt[a[j]] == maxn) {
maxx = min(maxx, a[j]);
}
}
f[i][k] = maxx;
}
}
}
pair<int, int> query5(int l, int r) {
int ans = 0, ansx;
pair<int, int> temp;
temp = {INF, 0};
if (bel[l] == bel[r]) {
memset(cnt, 0, sizeof cnt);
for (int i = l; i <= r; i++) {
cnt[a[i]]++;
if (cnt[a[i]] > temp.second) {
temp = {a[i], cnt[a[i]]};
} else if (cnt[a[i]] == temp.second) {
temp.first = min(temp.first, a[i]);
}
}
} else {
int tot;
for (int i = l; i <= ed[bel[l]]; i++) {
tot = count(a[i], l, r);
if (tot > temp.second) {
temp = {a[i], tot};
} else if (tot == temp.second) {
temp.first = min(temp.first, a[i]);
}
}
for (int i = st[bel[r]]; i <= r; i++) {
tot = count(a[i], l, r);
if (tot > temp.second) {
temp = {a[i], tot};
} else if (tot == temp.second) {
temp.first = min(temp.first, a[i]);
}
}
if (bel[l] + 1 < bel[r]) {
int t = f[bel[l] + 1][bel[r] - 1];
tot = count(t, l, r);
if (tot > temp.second) {
temp = {t, tot};
} else if (tot == temp.second) {
temp.first = min(temp.first, t);
}
}
}
return temp;
}
int main() {
cin >> n;
memset(num, -1, sizeof num);
for (int i = 1; i <= n; i++) {
cin >> a[i];
dis[++dis[0]] = a[i];
}
sort(dis + 1, dis + dis[0] + 1);
for (int i = 1; i <= dis[0]; i++) {
m[dis[i]] = i;
}
for (int i = 1; i <= n; i++) {
a[i] = m[a[i]];
}
for (int i = 1; i <= n; i++) {
v[a[i]].push_back(i);
}
int l, r, op;
ll c;
sq = sqrt(n);
init(n);
for (int i = 1; i <= n; i++) {
cin >> l >> r ;
cout << dis[query5(l, r).first] << endl;
}
}