• 分块&&莫队学习笔记


    坑太大了,一时甚至填不起来(现在只填到分块)


    分块和莫队都是非常好的暴力算法,

    能够让人在面对一些要求维护特殊序列的题时,可以拿到暴力高分甚至AC

    甚至还多次出现在各地省选中,学了不亏的好东西

    (但是还是要追求巧妙正解啊歪)


    分块

    分块,顾名思义,将数列切块,批量每个块上的答案信息,

    询问时如果询问区间覆盖了这个块,直接统计答案信息就行了,如果没有,就把这个块暴力拆开,查询里面的具体数据。

    修改时如果修改区间覆盖了这个块,给这个块打个标记,查询的时候再把标记处理给块内具体数据,如果不覆盖,就暴力拆开维护具体数据。

    具体来看题。


    Luogu P3870 [TJOI2009]开关

    • 有一个01序列,要求支持区间异或,区间查询的操作,强制在线。

    • 操作次数 = 序列长度 = 1e5

    线段树,分块,朴素暴力都可以A

    首先求出块长,然后求出块数,接着处理每个块的基本信息,然后小心维护就行了

    分块细节很多,我调了一下午,这里说几个蒟蒻错了的地方

    • 打tag的时候已经处理了答案,消tag时又处理了一遍答案......

    • 没有处理区间在一个块内的情况

    • 循环的时候i就是块的下标,结果循环里面对下标又求了一次下标......

    #include<bits/stdc++.h>
    
    using namespace std ;
    
    const int MAXN = 100010;
    int n,m;
    struct Block{
    	int l,r;
    	int ans,tag;
    }blo[1000];
    int fab[MAXN],a[MAXN],sq,bctr;
    
    void set_up(){
    	sq = sqrt(n);
    	bctr = n/sq;
    	if(n%sq) ++bctr;
    //		cout<<sq<<"<-sq bctr->"<<bctr<<endl;
    	for(int i=1;i<=n;i++){
    		fab[i] = (i-1)/sq+1;
    //			cout<<fab[i]<<" ";
    	}
    //		cout<<endl;
    	for(int i=1;i<bctr;i++){
    		blo[i].l = (i-1) * sq + 1;
    		blo[i].r = i * sq; 
    	}
    	blo[bctr].l = (bctr-1) * sq + 1;
    	blo[bctr].r = n;
    //	for(int i=1;i<=bctr;i++){
    //		cout<<"i = "<<i;
    //		cout<<" ans = "<<blo[i].ans;
    //		cout<<" tag = "<<blo[i].tag;
    //		cout<<" l = "<<blo[i].l<<" r = "<<blo[i].r<<endl;
    //	}
    }
    
    void pushdown(int x){//无脑push 
    //	if(blo[x].tag == 0) cout<<"???"<<endl;
    	for(int i=blo[x].l;i<=blo[x].r;i++)
    		a[i] ^= 1;
    	blo[x].tag = 0;
    }
    
    void change (int x,int y){
    	if(fab[x] == fab[y]){
    		if(blo[fab[x]].tag) pushdown(fab[x]);
    		for(int i=x;i<=y;i++){
    			a[i] ^= 1;
    			blo[fab[i]].ans += ((a[i] == 1) ? 1 : -1); 
    		}
    		return;
    	}
    /*-----------same block--------*/ 
    	if(blo[fab[x]].l != x){
    		if(blo[fab[x]].tag) pushdown(fab[x]);
    		for(int i=x;i<=blo[fab[x]].r;i++){
    			a[i] ^= 1;
    			blo[fab[i]].ans += (a[i] == 1) ? 1 : -1;
    		}
    	}
    	else {
    		blo[fab[x]].tag ^= 1;
    		blo[fab[x]].ans = (blo[fab[x]].r - blo[fab[x]].l + 1) - blo[fab[x]].ans;
    	}
    /*-----------left part---------*/
    	if(blo[fab[y]].r != y){
    		if(blo[fab[y]].tag) pushdown(fab[y]);
    		for(int i=blo[fab[y]].l;i<=y;i++){
    			a[i] ^= 1;
    			blo[fab[y]].ans += (a[i] == 1) ? 1 : -1;
    		}
    	}
    	else{
    		blo[fab[y]].tag ^= 1;
    		blo[fab[y]].ans = (blo[fab[y]].r - blo[fab[y]].l + 1) - blo[fab[y]].ans;
    	}
    /*-----------right part---------*/
    	for(int i=fab[x]+1;i<=fab[y]-1;i++){
    		blo[i].tag ^= 1;
    		blo[i].ans = (blo[i].r - blo[i].l + 1) - blo[i].ans;
    	}
    //	for(int i=1;i<=bctr;i++){
    //		cout<<blo[i].ans<<" ";
    //	}
    	
    	return;
    /*-----------middle part--------*/
    }
    
    int ask(int x,int y){
    	int ret = 0;
    	
    //		for(int i=1;i<=bctr;i++){
    //			cout<<blo[i].ans<<" ";
    //		}
    	
    	if(fab[x] == fab[y]){
    		if(blo[fab[x]].tag) pushdown(fab[x]);
    		for(int i=x;i<=y;i++){
    			ret += a[i];
    		}
    		return ret;
    	}
    	
    	if(x != blo[fab[x]].l) {
    		if(blo[fab[x]].tag) pushdown(fab[x]);
    		for(int i = x; i <= blo[fab[x]].r; i++) {
    			ret += a[i];
    		}
    	}
    	else ret += blo[fab[x]].ans;
    	
    //		for(int i=1;i<=bctr;i++){
    //			cout<<blo[i].ans<<" ";
    //		}
    	
    	if(y != blo[fab[y]].r) {
    		if(blo[fab[y]].tag) pushdown(fab[y]);
    		for(int i = blo[fab[y]].l; i <= y; i++) {
    			ret += a[i];
    		}
    	}
    	else ret += blo[fab[y]].ans;
    	
    //		for(int i=1;i<=bctr;i++){
    //			cout<<blo[i].ans<<" ";
    //		}
    	
    	for(int i=fab[x]+1;i<=fab[y]-1;i++){
    		ret += blo[i].ans;
    //		cout<<"ret = "<<ret<<endl;
    //		cout<<"i = "<<i<<endl;
    //		cout<<"blo[i].ans = "<<blo[i].ans<<endl;
    	}
    	return ret;
    }
    
    int main(){
    	ios::sync_with_stdio(false);
    	cin>>n>>m;
    	set_up();
    	for(int i=1;i<=m;i++){
    		int t,x,y;
    		cin>>t>>x>>y;
    		if(t == 0){
    			change(x,y);
    		}
    		if(t == 1){
    			cout<<ask(x,y)<<endl;
    		}
    //		cout<<"for this round,the ans1 and ans2 and ans3 is "<<blo[1].ans<<" "<<blo[2].ans<<" "<<blo[3].ans<<endl;
    	}
    	return 0;
    }
    

    百万丢人调试信息


    Luogu P4879 ycz的妹子

    这个题题面有坑,而且样例还查不出来,就很xie。

    大概概括一下,给你一个序列,要求支持单点修改,查询前缀和为x的位置,序列总和查询

    但是实际上题意要稍微复杂一点,建议去看原题

    分块搞,前缀和也是整块处理,散块暴力,弱菜的我这次又调了一个下午

    #include<bits/stdc++.h>
    
    using namespace std ;
    
    const int MAXN = 500010;
    struct Block{
    	int l,r,ctr;
    	long long ans;
    }blo[1010];
    int blen,bctr,fab[MAXN],n,m;
    bool book[MAXN];
    long long a[MAXN];
    
    struct Ord{
    	char typ;
    	int x;
    	long long y;
    }ord[MAXN];
    
    void set_up(){
    	blen = sqrt(n);
    	bctr = n/blen;
    	if(n%blen) bctr++;
    	for(int i=1;i<=n;i++){
    		fab[i] = (i - 1) / blen + 1;
    	}
    	for(int i=1;i<=n;i++){
    		blo[fab[i]].ans += a[i];
    	}
    	for(int i=1;i<bctr;i++){
    		blo[i].l = (i - 1) * blen + 1;
    		blo[i].r = i * blen;
    	}
    	blo[bctr].l = (bctr - 1) * blen + 1;
    	blo[bctr].r = n;
    	for(int i=1;i<=n;i++){
    		if(book[i] == true) blo[fab[i]].ctr++;
    		else break;
    	}
    	return;
    }
    
    void add(int x,long long y){
    	a[x] += y;
    	blo[fab[x]].ans += y;
    	return;
    }
    
    int get_pos(int x){
    	int ctr=0,ret = 0;
    	for(int i=1;i<=bctr;i++){
    		ctr += blo[i].ctr;
    		if(ctr>=x){
    			ctr -= blo[i].ctr;
    			ret = blo[i].l;
    			break;
    		}
    	}
    	while(1){
    		ctr += book[ret];
    		if(ctr == x) break;
    		ret++;
    	}
    	return ret;
    }
    
    void del(int x){
    	int tp = get_pos(x);
    	blo[fab[tp]].ans -= a[tp];
    	a[tp] = 0;
    	if(book[tp] == true) --blo[fab[tp]].ctr;
    	book[tp] = false;
    	return;
    }
    
    void change(int x,int y){
    	if(book[x] == false){
    		book[x] = true;
    		blo[fab[x]].ctr++;
    	}
    	blo[fab[x]].ans -= a[x];
    	a[x] = y;
    	blo[fab[x]].ans += a[x];
    	return;
    }
    
    long long ask(){
    	long long ret = 0;
    	for(int i=1;i<=bctr;i++){
    		ret += blo[i].ans;
    	}
    	return ret;
    }
    
    int main(){
    	ios::sync_with_stdio(false);
    	cin>>n>>m;
    	for(int i=1;i<=n;i++){
    		cin>>a[i];
    		book[i] = true;
    	}
    	for(int i=1;i<=m;++i){
    		cin>>ord[i].typ;
    		if(ord[i].typ == 'C'){
    			cin>>ord[i].x>>ord[i].y;
    		}
    		if(ord[i].typ == 'D'){
    			cin>>ord[i].x;
    		}
    		if(ord[i].typ == 'I'){
    			cin>>ord[i].x>>ord[i].y;
    			n=max(n,ord[i].x);
    		}
    	}
    	set_up();
    	for(int i=1;i<=m;i++){
    		if(ord[i].typ == 'Q'){
    			cout<<ask()<<endl;
    		}
    		if(ord[i].typ == 'C'){
    			add(ord[i].x,-ord[i].y);
    		}
    		if(ord[i].typ == 'D'){
    			del(ord[i].x);
    		}
    		if(ord[i].typ == 'I'){
    			change(ord[i].x,ord[i].y);
    		}
    	}
    	return 0;
    }
    

    我好菜啊,不过这个打的挺好看的

  • 相关阅读:
    仿百度翻页(转)
    文字顺时针旋转90度(纵向)&古诗词排版
    微信小程序使用canvas绘制图片的注意事项
    PHP即时实时输出内容
    使用Android Studio遇到的问题
    RuntimeError: Model class users.models.UserProfile doesn't declare an explicit app_label and isn't in an application in INSTALLED_APPS.
    drf中的各种view,viewset
    代码审计:covercms 1.6
    windows下安装phpredis扩展
    python练习:异常
  • 原文地址:https://www.cnblogs.com/SINXIII/p/11240348.html
Copyright © 2020-2023  润新知