概述
前言
首A黑题,虽然离不开题解,但是还是很激动
我的想法
首先我是想取维护区间的max,之后假如区间max小于x,那么我们就不用去递归了,之后如果大于就去分别处理,但是可以发现这个做法虽然也有均摊,但是当x很小时候无异于暴力,所以还是要优化
正解
首先是十分有用(** 毒 瘤 ** )的不均匀分块,我们取K(一个基数),之后按照【1,k)【k 2 , k 3) …这样去分块,
之后就可以最多分出来 log k a i log_k ai logkai个块。
我在每一个块上开一个线段树,之后线段数上维护区间最大值,区间和,区间最小值。
不均匀分块目的
我考虑一下按照均匀的值域分块,是不是每一次的修改量十分的大,而不均匀首先块的数量比较少,之后就是每一个数的掉落次数也最多是log次,之后就会有复杂度保证
空间问题
我们发现在线段树上的空间十分着急,怎么办,我们就用时间去换空间,首先线段树上最耗费空间的是不是叶子节点,我们就可以把叶子节点扩大,也就代表我们每一个叶子维护的是原数列的一些数(这里直接暴力处理就可以了,至于满足分块值域其实就在暴力里判断就好了)。
修改操作
首先分三类
小于x的块 ,不管
大于x的块,直接区间打标记修改是不是就好了
x这个块 , 比较麻烦,首先我们去考虑一下这个块也会分成两个部分
上面的我就取直接修改,之后就是看看会不会掉落到其他的块是不是,那么我就在暴力里取加入插入函数是不是就好了
至于x以下的是不是就不用管了
询问
是不是遍历每一个块,把答案综合起来是不是就好了
代码
#include<bits/stdc++.h>
#define ll long long
#define ls (num << 1)
#define rs (num << 1 | 1)
using namespace std;
const int maxn = 5e5 + 10 , B = 16 , K = 32 , df = 2e4 + 7;
void read(int &x){
int r = 0;
char s;
s = getchar();
while(s < '0' || s > '9') s = getchar();
while(s >= '0' && s <= '9'){
r = r * 10 + s - '0';
s = getchar();
}
x = r;
}
int n , m , a[maxn];
int mx[9][df << 1] , mn[9][df << 1];//max min
ll sum[9][df << 1] , lb[9] , rb[9];//区间和,块的左边界,右边界
ll ma[9][df << 1] , tag[9][df << 1];//区间有几个数, 懒标记
int getblk(int now){
int cnt = 1;
while(rb[cnt] < now){
cnt++;
}
return cnt;
}//查找值在那一块
void pushup(int blk , int num){
mx[blk][num] = max(mx[blk][ls] , mx[blk][rs]);
mn[blk][num] = min(mn[blk][ls] , mn[blk][rs]);
ma[blk][num] = ma[blk][ls] + ma[blk][rs];
sum[blk][num] = sum[blk][ls] + sum[blk][rs];
}
void pushdown(int blk , int num){
if(!tag[blk][num]) return;
tag[blk][ls] += tag[blk][num] * (ma[blk][ls] != 0);
tag[blk][rs] += tag[blk][num] * (ma[blk][rs] != 0);
if(ma[blk][ls]){
sum[blk][ls] -= ma[blk][ls] * tag[blk][num];
mn[blk][ls] -= tag[blk][num];
mx[blk][ls] -= tag[blk][num];
}
if(ma[blk][rs]){
sum[blk][rs] -= ma[blk][rs] * tag[blk][num];
mn[blk][rs] -= tag[blk][num];
mx[blk][rs] -= tag[blk][num];
}
tag[blk][num] = 0; return;
}
void blk_pushdown(int l,int r,int blk,ll &x){
if(!x) return;
for(int i = l; i <= r ; i++) if(a[i] >= lb[blk] && a[i] <= rb[blk]) a[i] -= x;
x = 0;//清除标记
return;
}//底层分块的下传信息,暴力传递 省空间
void blk_pushup(int l , int r , int blk , int num){
mn[blk][num] = INT_MAX;
mx[blk][num] = 0 ; sum[blk][num] = 0 ; ma[blk][num] = 0;
for(int i = l ; i <= r ; i++){
if(a[i] >= lb[blk] && a[i] <= rb[blk]){
sum[blk][num] += a[i] ;
ma[blk][num] ++;
mx[blk][num] = max(mx[blk][num] , a[i]);
mn[blk][num] = min(mn[blk][num] , a[i]);
}
} return;
}
//底层分块的上传信息
void insert(int blk , int num,int l,int r,int c,int d){
if(r - l + 1 <= K){
blk_pushdown(l , r , blk , tag[blk][num]);
a[c] = d;
blk_pushup(l , r , blk , num);
//cout<<sum[blk][num]<<endl;
return;//假如区间长度小于的话就直接对于序列暴力,之后就可以省空间
}
int mid = (l + r) >> 1;
pushdown(blk,num);
if(mid >= c) insert(blk,ls,l,mid,c,d);
else insert(blk,rs,mid+1,r,c,d);
pushup(blk,num);
}//插入点
void blk_update(int l,int r,int blk,int x){
for(int i = l ; i <= r; i++){
if (a[i] >= lb[blk] && a[i] <= rb[blk] && a[i] > x){
a[i] -= x;
if(a[i] < lb[blk]){
insert(getblk(a[i]),1,1,n,i,a[i]);
}//插入别的块里面
}
}
}
void blk_que(int blk,int l,int r,int c,int d,ll &ans,int &maxx,int &minn){
for(int i = max(l,c); i <= min(r,d) ; i++){
if(a[i] >= lb[blk] && a[i] <= rb[blk]){
ans += a[i] , maxx = max(maxx,a[i]) , minn = min(minn,a[i]);
}
}
return;
}
void update(int blk,int num,int l,int r,int c,int d,int x){
if(mx[blk][num] <= x) return;
if(r - l + 1 <= K){
blk_pushdown(l,r,blk,tag[blk][num]);
c = max(c,l) ; d = min(r,d);
blk_update(c,d,blk,x);
blk_pushup(l,r,blk,num);
return;
}
if(c <= l && r <= d && mn[blk][num] - lb[blk] >= x){
sum[blk][num] -= x * ma[blk][num] , mn[blk][num] -= x , mx[blk][num] -= x;
tag[blk][num] += x;
return;
}//如果完全包含直接打标记
int mid = (l + r) >> 1;
pushdown(blk,num);
if(mid >= c) update(blk,ls,l,mid,c,d,x);
if(mid < d) update(blk,rs,mid+1,r,c,d,x);
pushup(blk,num);
return;
}
//区间修改
void query(ll &ans, int &maxx, int &minn, int blk, int num, int l, int r,int c,int d){
if(c <= l && r <= d){
ans += sum[blk][num] ; maxx = max(maxx,mx[blk][num]) ; minn = min(minn,mn[blk][num]);
return;
}
if(r - l + 1 <= K){
blk_pushdown(l,r,blk,tag[blk][num]);
blk_que(blk,l,r,c,d,ans,maxx,minn);
blk_pushup(l,r,blk,num);
return;
}
int mid = (l + r) >> 1;
pushdown(blk,num);
if(c <= mid) query(ans,maxx,minn,blk,ls,l,mid,c,d);
if(d > mid) query(ans,maxx,minn,blk,rs,mid+1,r,c,d);
pushup(blk,num);
return;
}
int main(){
for(int i = 1; i <= 8; i++){
for(int j = 0; j <= df * 2 - 2; j++){
mn[i][j] = INT_MAX ; mx[i][j] = 0;
}
}//初始化最值
for(int i = 1; i <= 8 ; i ++) lb[i] = rb[i - 1] + 1 , rb[i] = lb[i] * B - 1;
read(n); read(m);
for(int i = 1; i <= n; i++){
read(a[i]);
int x = a[i];
insert(getblk(x) , 1 , 1 , n , i , x);
}
ll lastans = 0;
int maxx = 0 , minn = INT_MAX;
ll ans = 0;
while(m --){
int op;
read(op);
if(op == 1){
int x,y,z;
read(x) ; x ^= lastans;
read(y) ; y ^= lastans;
read(z) ; z ^= lastans;
for(int i = 1 ; i <= 8 ; i++) if(rb[i] >= x) update(i,1,1,n,x,y,z);
}
if(op == 2){
int x,y;
ans = 0 , maxx = 0,minn = INT_MAX;
read(x) ; x ^= lastans;
read(y) ; y ^= lastans;
for(int i = 1 ;i <= 8 ;i ++){
query(ans,maxx,minn,i,1,1,n,x,y);
}
printf("%lld %d %dn" , ans, minn , maxx);
lastans = ans % 1048576 ;
}
}
return 0;
}
最后
以上就是复杂雪糕为你收集整理的P7447 [Ynoi2007] rgxsxrs毒瘤数据结构前言我的想法正解代码的全部内容,希望文章能够帮你解决P7447 [Ynoi2007] rgxsxrs毒瘤数据结构前言我的想法正解代码所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复