高级数据结构分块莫队笛卡尔树算法模板几题

Posted quinn18

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了高级数据结构分块莫队笛卡尔树算法模板几题相关的知识,希望对你有一定的参考价值。

ahhhh留下点会议行不行


分块

模板
对区间加上k,求出某个区间的和

using namespace std;
#define int long long
const int N = 1e6+10;
int n, m, q;
int a[N], b[N];
int l[N], r[N];//存块的左右端点
int belong[N], add[N], sum[N];//belong表示属于哪个块
int B;
void update(int x, int y, int c) {
	if(belong[x]==belong[y]) {//在同一块里暴力更新
		for(int i=x; i<=y; i++) a[i]+=c;
		sum[belong[x]]+=(y-x+1)*c;
		return ;
	}
	for(int i=belong[x]+1; i<=belong[y]-1; i++) add[i]+=c;//好多块来个lazy标记
	for(int i=x; i<=r[belong[x]]; i++) a[i]+=c;//在同一块里暴力更新
	sum[belong[x]]+=(r[belong[x]]-x+1)*c;
	for(int i=l[belong[y]]; i<=y; i++) a[i]+=c;//在同一块里暴力更新
	sum[belong[y]]+=(y-l[belong[x]]+1)*c;
}
int ask(int x, int y) {
	int ans=0;
	if(belong[x]==belong[y]) {
		for(int i=x; i<=y; i++) ans+=a[i]+add[belong[x]];

		return ans;
	}
	for(int i=belong[x]+1; i<=belong[y]-1;i++) {
		ans+=sum[i]+add[i]*B;
    }
	for(int i=x; i<=r[belong[x]]; i++) ans+=a[i]+add[belong[x]];
	for(int i=l[belong[y]]; i<=y; i++) ans+=a[i]+add[belong[y]];
    return ans;
}
signed main() {
    cin>>n>>q;
    for(int i=1; i<=n; i++) cin>>a[i];
    B=sqrt(n);
	int num=(n+B-1)/B;
	for(int i=1; i<=n; i++) belong[i]=(i+B-1)/B, sum[belong[i]]+=a[i];
	for(int i=1; i<=num; i++) l[i]=(i-1)*B+1, r[i]=i*B;
	for(int i=1; i<=num; i++) sort(b+l[i], b+r[i]+1);
    int c, x, y, w;
    for(int i=1;i<=q;i++) {
        cin>>c>>x>>y;
        if(c==1) cin>>w, update(x, y, w);
        else cout<<ask(x, y)<<endl;
    }
    return 0;
}

给出一个长为 的数列,以及 个操作,操作涉及区间加法,询问区间内小于某个值 的前驱(比其小的最大元素)。
问块里小于c的想到二分
对于零散块的更新也要这个零散块的整个块进行sort
复杂度 O ( q ∗ s q r t ( N ) l o g ( s q r t ( N ) ) ) O(q*sqrt(N)log(sqrt(N))) O(qsqrt(N)log(sqrt(N)))

using namespace std;
#define int long long
const int N = 1e6+10;
int n, q, a[N], b[N], l[N], r[N], belong[N], add[N], B;
void reset(int x) {
	for(int i=l[belong[x]]; i<=r[belong[x]]; i++) b[i]=a[i];
	sort(b+l[belong[x]], b+r[belong[x]]+1);
}
void update(int x, int y, int c) {
	if(belong[x]==belong[y]) {
		for(int i=x; i<=y; i++) a[i]+=c;
		reset(x);
		return ;
	}
	for(int i=x; i<=r[belong[x]]; i++) a[i]+=c;
	for(int i=l[belong[y]]; i<=y; i++) a[i]+=c;
	reset(x);
	reset(y);
	for(int i=belong[x]+1; i<=belong[y]-1; i++) add[i]+=c;
}
int ask(int x, int y, int c) {
	int ans=-2e18;
	if(belong[x]==belong[y]) {
		for(int i=x; i<=y; i++) {
			if(a[i]+add[belong[x]]<c) ans=max(ans, a[i]+add[belong[x]]);
		}
		if(ans==-2e18) ans=-1;
		return ans;
	}
	for(int i=x; i<=r[belong[x]]; i++) if(a[i]+add[belong[x]]<c) ans=max(ans, a[i]+add[belong[x]]);
	for(int i=l[belong[y]]; i<=y; i++) if(a[i]+add[belong[y]]<c) ans=max(ans, a[i]+add[belong[y]]);
	for(int i=belong[x]+1; i<=belong[y]-1;i++) {
		int qq=lower_bound(b+l[i], b+r[i]+1, c-add[i])-b-1;//二分查找的是c-add[i]
		if(b[qq]<c-add[i]) ans=max(ans, b[qq]+add[i]);//这里调了好久 最后的ans要和b[qq]+add[i]比较不是b[i]//有可能是找不到就返回首位置就要if判断一下
    }
    if(ans==-2e18) ans=-1;
    return ans;
}

莫队

P4137 Rmq Problem / mex莫队+分块
求区间mex直接分块
询问通过分块sort一下然后莫队跑

using namespace std;
const int N = 2e5 + 5;
const int B = sqrt(N);
int a[N], cnt[N], n, m, tans, ans[N], zhengge[N];//记整个块内有的数的数量
int l=1, r=0;//一直t一个点把l=1,r=0;从主函数搬到外面就不t了。。。。快了0.03s
struct Q {
    int l, r, id;
	bool operator<(const Q &t) const {
        return l/B==t.l/B ? r<t.r: l/B<t.l/B;
    }
}q[N];
int get(int x) {return x/B;}
void update(int x, int f) {
	cnt[x]+=f;
    if(cnt[x]==0&&f==-1) zhengge[get(x)]+=f;
    else if(cnt[x]==1&&f==1) zhengge[get(x)]+=f;
}
int main() {
    n=read(); m=read();
    for(int i=1; i<=n; i++) a[i]=read();
    for(int i=1; i<=m; i++) {
		q[i].l=read();q[i].r=read();
		q[i].id=i;
    }
    sort(q+1, q+m+1);
    for(int i=1; i<=m; i++) {
        while(l<q[i].l) update(a[l++], -1);
        while(l>q[i].l) update(a[--l], 1);
        while(r<q[i].r) update(a[++r], 1);
        while(r>q[i].r) update(a[r--], -1);
		int qq=0;
		for(int k=0; k<=B; k++) {
			if(zhengge[k]<B) {
				for(int j=k*B; j<=k*B+B-1; j++) {
					if(cnt[j]==0) {
						ans[q[i].id]=j;
						qq=1;
						break;
					}
				}
			}
			if(qq) break;
		}
    }
    for(int i=1; i<=m; i++) {
		cout<<ans[i]<<"\\n";
    }
    return 0;
}

XOR and Favorite Numbercf2200
求区间段异或所以想到存区间前缀和
假设现在位置为 R R R,异或前缀和为 x x x,我们需要多少个左区间满足 x x x^ p r e [ L − 1 ] = = k pre[L-1]==k pre[L1]==k 等价于有多少个 p r e [ L − 1 ] = = x pre[L-1]==x pre[L1]==x ^ k k k,用一个桶去装
但是由于区间 [ L , R ] [L, R] [L,R]的异或值为 p r e [ R ] pre[R] pre[R] ^ p r e [ L − 1 ] pre[L-1] pre[L1]所以需要把左端点移动一下

#define int long long//tans和ans[]都会爆int 找学长找了bug
using namespace std;
const int N = 2e6 + 5;
int a[N], cnt[N], n, m, k, tans, ans[N], B;
struct Q {
    int l, r, id;
	bool operator<(const Q &t待更新算法

[学习-思考-探究]莫队算法 曼哈顿最小生成树与分块区间询问算法

BZOJ3052: [wc2013]糖果公园 树分块+待修改莫队算法

[学习-思考-探究]莫队算法 曼哈顿最小生成树与分块区间询问算法-3

[学习-思考-探究]莫队算法 曼哈顿最小生成树与分块区间询问算法-4

[学习-思考-探究]莫队算法 曼哈顿最小生成树与分块区间询问算法-2