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 。。。。 我也是很无奈,, 不知道为啥