CDQ分治练习

 

cdq分治解决偏序整体二分解决区间k小思路相似,都是考虑左区间对右区间的影响,但是实现略有不同

偏序的重点是:理解两个有序链表的合并,即,一次归并排序

整体二分的重点是:二分权值,把操作(查询与修改)划分到左右区间,然后递归处理

 

 

陌上花开

x排序,y分治,z树状数组

/*author:revolIA*/
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e5+7;
int Tree[maxn],n,k;
int out[maxn];
void Add(int x,int val){
    for(;x<=k;x+=x&-x)Tree[x] += val;
}
int query(int x,int ans = 0){
    for(;x;x-=x&-x)ans += Tree[x];
    return ans;
}
struct node{
    int x,y,z;
    int ans,w;
    bool operator < (const node &T)const{
        if(x != T.x)return x<T.x;
        if(y != T.y)return y<T.y;
        return z<T.z;
    }
    bool operator == (const node T)const{
        return (x == T.x)&&(y == T.y)&&(z == T.z);
    }
}Qt[maxn],Tmp[maxn];
void CDQ(int l,int r){
    if(l == r)return ;
    int mid = l+r>>1;
    CDQ(l,mid),CDQ(mid+1,r);
    int L = l,R = mid+1,cnt = l;
    while(L<=mid && R<=r){
        if(Qt[L].y<=Qt[R].y){
            Add(Qt[L].z,Qt[L].w);
            Tmp[cnt++] = Qt[L++];
        }else{
            Qt[R].ans += query(Qt[R].z);
            Tmp[cnt++] = Qt[R++];
        }
    }
    while(R<=r){
        Qt[R].ans += query(Qt[R].z);
        Tmp[cnt++] = Qt[R++];
    }
    for(int i=l;i<L;i++)Add(Qt[i].z,-Qt[i].w);
    while(L<=mid)Tmp[cnt++] = Qt[L++];
    for(int i=l;i<=r;i++)Qt[i] = Tmp[i];
}
int main(){
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++)scanf("%d%d%d",&Tmp[i].x,&Tmp[i].y,&Tmp[i].z);
    sort(Tmp+1,Tmp+1+n);
    int cnt = 0,pos = 1;
    while(pos<=n){
        Qt[++cnt] = Tmp[pos];
        Qt[cnt].w = 1;
        Qt[cnt].ans = 0;
        while(pos<n && Tmp[pos] == Tmp[pos+1]){
            Qt[cnt].w++;
            pos++;
        }
        pos++;
    }
    CDQ(1,cnt);
    for(int i=1;i<=cnt;i++)out[Qt[i].ans+Qt[i].w-1] += Qt[i].w;
    for(int i=0;i<n;i++)printf("%d\n",out[i]);
    return 0;
}

 

cogs577.蝗灾

统计矩阵内点数(可带权)

 

/*author:revolIA*/
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e6+7;
int Tree[maxn],ans[maxn],w,n,cnt,tot;
void add(int x,int val){while(x<=w)Tree[x] += val,x+=x&-x;}
int query(int x,int ans = 0){while(x)ans += Tree[x],x-=x&-x;return ans;}
struct node{
    int x,y,w;
    int pos,opt;
}Qt[maxn],Tmp[maxn];
void CDQ(int l,int r){
    if(l == r)return;
    int mid = l+r>>1;
    CDQ(l,mid),CDQ(mid+1,r);
    int L = l,R = mid+1,cnt = l;
    while(L<=mid && R<=r){
        if(Qt[L].x <= Qt[R].x){
            if(!Qt[L].opt)add(Qt[L].y,Qt[L].w);
            Tmp[cnt++] = Qt[L++];
        }else{
            if(Qt[R].opt == 1)ans[Qt[R].pos] -= query(Qt[R].w)-query(Qt[R].y-1);
            if(Qt[R].opt == 2)ans[Qt[R].pos] += query(Qt[R].w)-query(Qt[R].y-1);
            Tmp[cnt++] = Qt[R++];
        }
    }
    while(R<=r){
        if(Qt[R].opt == 1)ans[Qt[R].pos] -= query(Qt[R].w)-query(Qt[R].y-1);
        if(Qt[R].opt == 2)ans[Qt[R].pos] += query(Qt[R].w)-query(Qt[R].y-1);
        Tmp[cnt++] = Qt[R++];
    }
    for(int i=l;i<L;i++)if(!Qt[i].opt)add(Qt[i].y,-Qt[i].w);
    while(L<=mid)Tmp[cnt++] = Qt[L++];
    for(int i=l;i<=r;i++)Qt[i] = Tmp[i];
}
int main(){
    freopen("locust.in","r",stdin);
    freopen("locust.out","w",stdout);
    scanf("%d%d",&w,&n);
    for(int i=1,opt,x,y,z;i<=n;i++){
        scanf("%d",&opt);
        if(opt == 1){
            scanf("%d%d%d",&x,&y,&z);
            Qt[++cnt] = {x,y,z,0,0};
        }else{
            ++tot;
            scanf("%d%d%d%d",&x,&y,&z,&opt);
            if(x>z)swap(x,z);
            if(y>opt)swap(y,opt);
            Qt[++cnt] = {x-1,y,opt,tot,1};
            Qt[++cnt] = {z,y,opt,tot,2};
        }
    }
    CDQ(1,cnt);
    for(int i=1;i<=tot;i++)printf("%d\n",ans[i]);
    return 0;
}

 

 

整体二分,静态区间第k小(主席树)

洛谷p3834

 

/*author:revolIA*/
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 4e5+7,inf = 1e9+7;
int Tree[maxn],n,m;
int ans[maxn];
void Add(int x,int val){
    for(;x<=n;x+=x&-x)Tree[x] += val;
}
int query(int x,int ans = 0){
    for(;x;x-=x&-x)ans += Tree[x];
    return ans;
}
struct node{
    int x,y,k;
    int pos,opt;
}Qt[maxn],Tmp[maxn];
void CDQ(int l,int r,int L,int R){
	if(l>r || L>R)return;
    if(l == r){
    	for(int i=L;i<=R;i++)if(Qt[i].opt){
    		ans[Qt[i].pos] = l;
    	}
    	return;
    }
    int mid = (l+r)>>1;
    int cnl = L,cnr = R;
    for(int i=L;i<=R;i++){
    	if(Qt[i].opt){
    		int sum = query(Qt[i].y)-query(Qt[i].x-1);
    		if(sum<Qt[i].k){
    			Qt[i].k -= sum,Tmp[cnr--] = Qt[i];
    		}else{
    			Tmp[cnl++] = Qt[i];
    		}
    	}else{
    		if(Qt[i].x<=mid){
    			Add(Qt[i].pos,1),Tmp[cnl++] = Qt[i];
    		}else{
    			Tmp[cnr--] = Qt[i];
    		}
    	}
    }
    for(int i=L;i<cnl;i++)if(!Tmp[i].opt)Add(Tmp[i].pos,-1);
    for(int i=L;i<=R;i++){
    	Qt[i] = i<cnl?Tmp[i]:Tmp[R-i+cnl];
    }
    CDQ(l,mid,L,cnl-1),CDQ(mid+1,r,cnr+1,R);
}
int main(){
	int Ml = inf,Mr = -inf;
    scanf("%d%d",&n,&m);
    for(int i=1,x;i<=n;i++){
    	scanf("%d",&x);
    	Qt[i] = {x,0,0,i,0};
    	Ml = Ml<x?Ml:x;
    	Mr = Mr>x?Mr:x;
    }
    for(int i=1,x,y,k;i<=m;i++){
    	scanf("%d%d%d",&x,&y,&k);
    	Qt[i+n] = {x,y,k,i,1};
    }
    CDQ(Ml,Mr,1,n+m);
    for(int i=1;i<=m;i++)printf("%d\n",ans[i]);
    return 0;
}

 

整体二分,动态区间k小(带修主席树)

Zoj2112.Dynamic Rankings

 

/*author:revolIA*/
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 4e5+7,inf = 1e9+7;
int Tree[maxn],n,m,a[maxn];
int ans[maxn],tot,cnt;
void Add(int x,int val){
    for(;x<=n;x+=x&-x)Tree[x] += val;
}
int query(int x,int ans = 0){
    for(;x;x-=x&-x)ans += Tree[x];
    return ans;
}
struct node{
    int x,y,k;
    int pos,opt;
}Qt[maxn],Tmp[maxn];
void CDQ(int l,int r,int L,int R){
	if(l>r || L>R)return;
    if(l == r){
    	for(int i=L;i<=R;i++)if(Qt[i].opt>0){
    		ans[Qt[i].pos] = l;
    	}
    	return;
    }
    int mid = (l+r)>>1;
    int cnl = L,cnr = R;
    for(int i=L;i<=R;i++){
    	if(Qt[i].opt>0){
    		int sum = query(Qt[i].y)-query(Qt[i].x-1);
    		if(sum<Qt[i].k){
    			Qt[i].k -= sum,Tmp[cnr--] = Qt[i];
    		}else{
    			Tmp[cnl++] = Qt[i];
    		}
    	}else{
    		if(Qt[i].x<=mid){
    			Add(Qt[i].pos,Qt[i].opt?-1:1);
    			Tmp[cnl++] = Qt[i];
    		}else{
    			Tmp[cnr--] = Qt[i];
    		}
    	}
    }
    for(int i=L;i<cnl;i++)if(Tmp[i].opt<=0)Add(Tmp[i].pos,Tmp[i].opt?1:-1);
    for(int i=L;i<=R;i++){
    	Qt[i] = i<cnl?Tmp[i]:Tmp[R-i+cnl];
    }
    CDQ(l,mid,L,cnl-1),CDQ(mid+1,r,cnr+1,R);
}
char opt[10];
int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        cnt = tot = 0;
        int Ml = inf,Mr = -inf;
        scanf("%d%d",&n,&m);
        for(int i=1,x;i<=n;i++){
            scanf("%d",&x);
            a[i] = x;
            Qt[++cnt] = {x,0,0,i,0};//insert
            Ml = Ml<x?Ml:x;
            Mr = Mr>x?Mr:x;
        }
        for(int i=1,x,y,k;i<=m;i++){
            scanf("%s",opt);
            if(opt[0] == 'Q'){
                scanf("%d%d%d",&x,&y,&k);
                Qt[++cnt] = {x,y,k,++tot,1};//ask
            }else{
                scanf("%d%d",&x,&y);
                Qt[++cnt] = {a[x],0,0,x,-1};//delete
                Qt[++cnt] = {y,0,0,x,0};//insert
                a[x] = y;
            }
        }
        CDQ(Ml,Mr,1,cnt);
        for(int i=1;i<=tot;i++)printf("%d\n",ans[i]),ans[i] = 0;
    }
    return 0;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值