偏序问题 cdq分治

偏序问题

b站学习链接
偏序问题是什么?
比如要找比当前数小的个数,
如果有两个值呢?
要求ai <= aj && bi <= bj 的i的个数
三个呢?
ai <= aj && bi <= bj && ci <= cj
说的可能不清楚,, 语言表达不够。。
但是没关系,我看得懂就行 hhhhhhh

一维的:

一维排个序就好。。

二维的:

按一个值排个序。
然后从前往后扫,把另一个值加到树状数组里然后 胡乱搞搞

三维的:

但是没关系,我看得懂就行 hhhhhhh
三维怎么弄?
按a值排序,然后按b值cdq分治,把c值加到数据结构里计算,,
cdq分治是个啥?
分治嘛就是分成子问题,然后合并答案
cdq分治就是 把数组分成两半,然后算前半对后半查询的贡献。。
因为是按a值排完序的然后左半间的a肯定小于右半区间的b的然后左右区间按b排序不好说。。 仔细想想就好了。
只算左半区间对右半的贡献,那右半区间对右半查询的贡献呢?当分治到右半的时候就算上了。。
然后四维呢?
按a排序,b cdq分治 c再分治 d数据结构维护,,
基本都可以这样但是时间复杂度呢?
如果维数高的话大佬说时间复杂度比n方还大,还不如n方。。
然后三维的话时间复杂度是个nlog2n吧,,大佬说的,,分治的时间复杂度我不咋会算。。

例题:

hdu 5126
题意:一个三维的坐标轴,有q(5e4)次询问,
询问:
1 x y z 给坐标上加一个xyz这个点
2 x1 y1 z1 x2 y2 z2 询问x1 y1 z1 ~ x2 y2 z2 这个矩形里有多少个点?
xyz都是1e9的
题解
因为长方体里的可以容斥掉
所以可以简化为询问小于x y z 的有多少个点?
就是x1 <= x y1 <= y z1 <= z 还有一个条件就是 时间轴
所以是四维偏序问题,,
好了上代码:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;

typedef long long ll;
const int maxn = 5e4+5;
struct Node
{
	int x,y,z;
	int f,id;
	Node(){}
	Node(int xx,int yy,int zz,int ff,int idd) : x(xx), y(yy), z(zz), f(ff), id(idd){}
};
std::vector<Node> vv;
std::vector<int> ls;
int getid(int x)
{
	return lower_bound(ls.begin(), ls.end(), x) - ls.begin() + 1;
}
void inst(int x,int y,int z,int f,int id)
{
	vv.push_back(Node(x,y,z,f,id));
}
std::vector<Node> node;
std::vector<Node> vp;

bool cmp2(Node a,Node b)
{
	if(a.y != b.y)
		return a.y < b.y;
	return a.id < b.id;
}
int ans[maxn];
const int M = 1e5 + 5;
int tree[M];
int lb(int x)
{
	return x & -x;
}
void add(int x,int num)
{
	while(x < M)
	{
		tree[x] += num;
		x += lb(x);
	}
}
int query(int x)
{
	int ans = 0;
	while(x > 0)
	{
		ans += tree[x];
		x -= lb(x);
	}
	return ans;
}


void solve()
{
	for (int i = 0; i < vp.size(); i ++ )
	{
		if(vp[i].f == 0)
		{
			add(vp[i].z,1);
		}
		else
		{
			ans[vp[i].id] += vp[i].f * query(vp[i].z);
		}
	}
	for (int i =0 ; i < vp.size(); i ++ )
	{
		if(vp[i].f == 0)
			add(vp[i].z,-1);
	}
}

void dfs2(int l,int r)
{
	// printf("%d %d 2\n",l,r);
	if(l >= r)
		return;
	int mid = l + r >> 1;
	dfs2(l,mid);
	vp.clear();
	for (int i = l; i <= mid; i ++ )
	{
		if(node[i].f == 0)
			vp.push_back(node[i]);
	}
	for (int i = mid + 1; i <= r; i ++ )
	{
		if(node[i].f != 0)
			vp.push_back(node[i]);
	}
	sort(vp.begin(),vp.end(),cmp2);
	solve();
	dfs2(mid + 1, r);
}


bool cmp(Node a, Node b)
{
	if(a.x != b.x)
		return a.x < b.x;
	return a.id < b.id;
}
void cdq(int l,int r)
{
	// printf("%d %d\n",l,r);
	if(l >= r)
		return;
	int mid = l + r >> 1;
	cdq(l,mid);
	node.clear();
	for (int i = l; i <= mid; i ++ )
	{
		if(vv[i].f == 0)
			node.push_back(vv[i]);
	}
	for (int i = mid + 1; i <= r; i ++ )
	{
		if(vv[i].f != 0)
			node.push_back(vv[i]);
	}
	sort(node.begin(),node.end(),cmp);
	dfs2(0,node.size() - 1);
	cdq(mid + 1, r);
}
std::vector<int> ansid;


void init()
{
	ansid.clear();
	vv.clear();
	memset(ans,0,sizeof(ans));
	ls.clear();
}

int main()
{
	int T;
	scanf("%d",&T);
	while(T -- )
	{
		init();
		int q;
		scanf("%d",&q);
		for (int i = 1; i <= q; i ++ )
		{
			int f;
			scanf("%d",&f);
			if(f == 1)
			{
				int x,y,z;
				scanf("%d%d%d",&x,&y,&z);
				ls.push_back(z);
				inst(x,y,z,0,i);
			}
			else
			{
				ansid.push_back(i);
				int x1,y1,z1,x2,y2,z2;
				scanf("%d%d%d%d%d%d",&x1,&y1,&z1,&x2,&y2,&z2);
				/*
				-1
				x1 - 1  y2      z2 
				x2      y1 - 1  z2 
				x2      y2      z1 - 1
				x1 - 1  y1 - 1  z1 - 1
				1
				x1 - 1  y1 - 1  z2
				x2      y1 - 1  z1 - 1
				x1 - 1  y2      z1 - 1
				x2      y2      z2
				*/
				inst(x1-1,y2,z2,-1,i);
				inst(x2,y1-1,z2,-1,i);
				inst(x2,y2,z1-1,-1,i);
				inst(x1-1,y1-1,z1-1,-1,i);
				inst(x1-1,y1-1,z2,1,i);
				inst(x2,y1-1,z1-1,1,i);
				inst(x1-1,y2,z1-1,1,i);
				inst(x2,y2,z2,1,i);
				ls.push_back(z1-1);
				ls.push_back(z2);
			}
		}
		sort(ls.begin(),ls.end());
		ls.erase(unique(ls.begin(),ls.end()),ls.end());
		for (int  i= 0; i < vv.size(); i ++ )
		{
			vv[i].z = getid(vv[i].z);
		}
		cdq(0,vv.size() - 1);
		for (int i = 0; i < ansid.size(); i ++ )
		{
			printf("%d\n",ans[ansid[i]]);
		}
	}

}

用G++可以过 用C++ tle 。。。。 我也是很无奈,, 不知道为啥

你可能感兴趣的:(学习笔记)