cdq分治

2 篇文章 0 订阅

对于能用cdq分治的题目需要满足3个条件
可以离线
修改不会相互影响
询问不会相互影响

归并排序求逆序对以及二维偏序很好的对cdq分治做了一个样例
这里就不在赘述

cdq分治处理单点修改,区间查询,可离线

首先,单点修改,区间查询,可离线,刚好满足cdq分治的使用要求
那么考虑怎么用cdq分治的思想解决这个问题

考虑现在有两段操作 依次按照 操作序号的大小以及先修改再查询有序

对于为什么每次只处理左端的修改,以及右端的询问,可以通过一张图来看在这里插入图片描述
比如说,我现在有个询问,在划圈处
很显然,有两段对他做了操作在这里插入图片描述

在比如对于一个修改,他能影响的范围如图
在这里插入图片描述
蓝色部分是他的修改范围

可以浅显的认为 cdq分治就是对于操作的的范围做的处理,使得操作不漏不多(比较妙)但我这个沙茶是学不会的啦

#include<bits/stdc++.h>
#define MAXN 700005
typedef long long ll;
using namespace std;

int n,m,tot,js,ans[MAXN];

struct node{
	int tp,val,id;
}t[MAXN * 3] , t2[MAXN * 3];

bool operator < (node x , node y){
	return ((x.id == y.id) ? (x.tp < y.tp) : (x.id < y.id));
}


void init(){
	cin>>n>>m;
	for(int i = 1 ; i <= n ; i++){
		tot++;
		t[tot].tp = 1;
		cin>>t[tot].val;
		t[tot].id = i;
	}
	int x,y,z;
	for(int i = 1 ; i <= m ; i++){
		cin>>x;
		if(x == 1){
			tot++;
			t[tot].tp = 1;
			cin>>t[tot].id;
			cin>>t[tot].val;
		}
		else{
			tot++ , js++;
			t[tot].tp = 2;
			t[tot].val = js;
			cin>>t[tot].id;
			t[tot].id--;
			
			tot++;
			t[tot].tp = 3;
			t[tot].val = js;
			cin>>t[tot].id;
		}
	}
}

void solve(int l , int r){
	if(l == r)return;
	int mid = (l + r) >> 1;
	int l1 = l , l2 = mid + 1 , len = l;
	solve(l , mid) , solve(mid + 1 , r);
	ll sum = 0;
	while(l1 <= mid && l2 <= r){
		if(t[l1] < t[l2]){
			if(t[l1].tp == 1)sum = sum + t[l1].val;
			t2[len] = t[l1] , len++ , l1++;
		}
		else{
			if(t[l2].tp == 2)ans[t[l2].val] -= sum;
			if(t[l2].tp == 3)ans[t[l2].val] += sum;
			t2[len] = t[l2] , len++ , l2++;
		}
	}
	while(l1 <= mid){
		if(t[l1].tp == 1)sum = sum + t[l1].val;
		t2[len] = t[l1] , len++ , l1++;
	}
	while(l2 <= r){
		if(t[l2].tp == 2)ans[t[l2].val] -= sum;
		if(t[l2].tp == 3)ans[t[l2].val] += sum;
		t2[len] = t[l2] , len++ , l2++;
	}
	for(int i = l ; i <= r ; i++)t[i] = t2[i];
}

int main(){
	init();
	solve(1 , tot);
	for(int i = 1 ; i <= js ; i++)cout<<ans[i]<<endl;
}

P3810 【模板】三维偏序(陌上花开)

结合魔板,成功A掉这个题。。。我这屑人就这样了

有个关键点,cdq分治不能有重复元素

#include<bits/stdc++.h>
#define MAXN 900005
using namespace std;

int n,k,q[MAXN],ans[MAXN],tot,cnt[MAXN];

struct node{
	int a,b,c,id;
}t[MAXN],t2[MAXN];

bool cmp(node x , node y){
	return ((x.a == y.a) ? (((x.b == y.b) ? (x.c < y.c) : (x.b < y.b))) : (x.a < y.a));
}

int lowbit(int x){
	return x & (-x);
}

int que(int x){
	int zz = 0;
	while(x){
		zz += q[x];
		x = x - lowbit(x);
	}
	return zz;
}

void clear(int x){
	while(x <= k){
		q[x] = 0;
		x += lowbit(x);
	}
}

void update(int x , int y){
	while(x <= k){
		q[x] += y;
		x = x + lowbit(x);
	}
}

void solve(int l , int r){
	if(l == r)return;
	int mid = (l + r) >> 1 , l1 = l , l2 = mid + 1 , len = l;
	solve(l , mid) , solve(mid + 1 , r);
	while(l1 <= mid && l2 <= r){
		if(t[l1].b <= t[l2].b){
			update(t[l1].c , cnt[t[l1].id]);
			t2[len] = t[l1] , len++ , l1++;
		}
		else{
			ans[t[l2].id] = ans[t[l2].id] + que(t[l2].c);
			t2[len] = t[l2] , len++ , l2++;
		}
	}
	while(l1 <= mid){
		t2[len] = t[l1] , len++ , l1++;
	}
	while(l2 <= r){
		ans[t[l2].id] = ans[t[l2].id] + que(t[l2].c);
		t2[len] = t[l2] , len++ , l2++;
	}
	for(int i = l ; i <= r ; i++)t[i] = t2[i];
	for(int i = l ; i <= r ; i++)clear(t[i].c);
	
}

int main(){
//	freopen("P3810_2.in" , "r" , stdin);
//	freopen("out.txt" , "w" , stdout);
	cin>>n>>k;
	for(int i = 1 ; i <= n ; i++)cin>>t2[i].a>>t2[i].b>>t2[i].c;
	sort(t2 + 1 , t2 + 1 + n , cmp);
	for(int i = 1 ; i <= n ; i++){
		if(t2[i].a != t[tot].a || t2[i].b != t[tot].b || t2[i].c != t[tot].c){
			tot++ , t[tot] = t2[i] , cnt[tot] = 1 , t[tot].id = tot;
		}
		else cnt[tot]++;
	}
	for(int i = 1 ; i <= tot ; i++)ans[i] = cnt[i] - 1;
	sort(t + 1 , t + 1 + tot , cmp);
	solve(1 , tot);
	memset(q , 0 ,sizeof(q));
	for(int i = 1 ; i <= tot ; i++)q[ans[i]] += cnt[i];
	for(int i = 0 ; i < n ; i++)cout<<q[i]<<endl;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值