其实这只是一道题的题解= =;
博主太弱不会T1T3;
然而我还是要吐槽一下,T2难道你们就没有一点写数据结构的心情吗!
T1:
留坑(不太可能填);
T2:
题意:
给出大小为n的一个四维点集,和m次询问;
每次询问给出一个点,求四维坐标均小于等于这个点的集合大小;
n,m<=30000;
题解:
看到这题的第一反应是排序乱搞,noip难度应该随便玩玩就过了嘛(笑);
但是仔细看看不是这么回事!
bzoj有一道题叫陌上花开——然而那个是三维的;
回忆一下,PoPoQQQ让我们搞排序+CDQ分治+树状数组;
hzwer让我们搞排序+树状数组套平衡树;
反正都是降维,综合一下,就是排序+CDQ分治+树状数组套平衡树不就搞出来了!
码!
具体搞法和一般的CDQ分治差不多,只是插入查询树状数组改成了树状数组套平衡树;
每次插入查询都是时间是O(log^2n)的,总体算上CDQ分治;
时间复杂度O(nlog^3n),空间复杂度O(nlogn);
这个效率还是不错的,但是正解并不是这个;
正解是用bitset来维护集合的交;
每次关于一维排序,求每个询问在这一维上小于等于的点集,用一个bitset记录;
然后将这些bitset与(&)起来,得到的集合就是最后的点集;
复杂度O(4*n^2/32),效率比上面的高级数据结构快一些,并且极为好写;
正解的做法还可以再向高维拓展,而高级数据结构就很难继续了;
(正解代码懒得写了,大家理解一下应该都是可以yy的(笑));
//更新:bitset正解的代码见下面;
代码:
排序+CDQ分治+树状数组套平衡树:
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 31000
#define lson tr[tr[x].l]
#define rson tr[tr[x].r]
using namespace std;
struct node
{
double a, b, c, d;
int num_ans, no;
}t[N << 1], temp[N << 1];
struct treap
{
double val;
int size, rnd, l, r;
void clear()
{
size = 1, rnd = rand(), l = 0, r = 0;
}
}tr[N * 20];
double dis[N << 1];
int len, cnt, ans[N];
int root[N << 1];
bool cmp1(node a, node b)
{
if (a.a == b.a)
return a.num_ans<b.num_ans;
return a.a < b.a;
}
bool cmp2(node a, node b)
{
return a.b < b.b;
}
int lowbit(int x)
{
return x&(-x);
}
void Pushup(int x)
{
tr[x].size = lson.size + rson.size + 1;
}
void lturn(int &x)
{
int t = tr[x].r;
tr[x].r = tr[t].l;
tr[t].l = x;
tr[t].size = tr[x].size;
Pushup(x);
x = t;
}
void rturn(int &x)
{
int t = tr[x].l;
tr[x].l = tr[t].r;
tr[t].r = x;
tr[t].size = tr[x].size;
Pushup(x);
x = t;
}
void Insert(int &x, double val)
{
if (!x)
{
tr[x = ++cnt].clear();
tr[x].val = val;
return;
}
tr[x].size++;
if (val <= tr[x].val)
{
Insert(tr[x].l, val);
if (tr[x].rnd < lson.rnd)
rturn(x);
}
else
{
Insert(tr[x].r, val);
if (tr[x].rnd > rson.rnd)
lturn(x);
}
}
int query(int x, double val)
{
if (!x) return 0;
if (tr[x].val > val)
return query(tr[x].l, val);
else
return lson.size + 1 + query(tr[x].r, val);
}
void add(int k, double val)
{
while (k <= len)
{
Insert(root[k], val);
k += lowbit(k);
}
}
void clear(int k)
{
while (k <= len && root[k])
{
root[k] = 0;
k += lowbit(k);
}
}
int getans(int k, double val)
{
int ret = 0;
while (k)
{
ret += query(root[k], val);
k -= lowbit(k);
}
return ret;
}
void divide(int l, int r)
{
int mid = l + r >> 1;
memcpy(temp + l, t + l, sizeof(node)*(r - l + 1));
for (int i = l, j = l, k = mid + 1; i <= r; i++)
{
if (temp[i].no <= mid)
t[j++] = temp[i];
else
t[k++] = temp[i];
}
}
void merge(int l, int r)
{
int mid = l + r >> 1;
memcpy(temp + l, t + l, sizeof(node)*(r - l + 1));
for (int i = l, j = l, k = mid + 1; i <= r; i++)
{
if (j <= mid&&k <= r)
t[i] = temp[j].b < temp[k].b ? temp[j++] : temp[k++];
else
t[i] = (j == mid + 1 ? temp[k++] : temp[j++]);
}
}
void slove(int l, int r)
{
if (l == r) return;
divide(l, r);
int mid = l + r >> 1, i, j;
slove(l, mid);
for (i = mid + 1, j = l, cnt = 0; i <= r; i++)
{
while (j <= mid&&t[j].b <= t[i].b)
{
if (!t[j].num_ans)
{
add(lower_bound(dis + 1, dis + len + 1, t[j].c) - dis, t[j].d);
}
j++;
}
if (t[i].num_ans)
{
ans[t[i].num_ans] += getans(lower_bound(dis + 1, dis + len + 1, t[i].c) - dis, t[i].d);
}
}
while (j >= l)
{
if (!t[j].num_ans)
{
clear(lower_bound(dis + 1, dis + len + 1, t[j].c) - dis);
}
j--;
}
slove(mid + 1, r);
merge(l, r);
}
int main()
{
int n, m, i, j, k;
scanf("%d", &n);
for (i = 1; i <= n; i++)
{
scanf("%lf%lf%lf%lf", &t[i].a, &t[i].b, &t[i].c, &t[i].d);
}
scanf("%d", &m);
for (i = 1; i <= m; i++)
{
scanf("%lf%lf%lf%lf", &t[i + n].a, &t[i + n].b, &t[i + n].c, &t[i + n].d);
t[i + n].num_ans = i;
dis[i + n] = t[i + n].c;
}
sort(dis + 1, dis + n + m + 1);
len = unique(dis + 1, dis + n + m + 1) - dis - 1;
sort(t + 1, t + n + m + 1, cmp1);
for (i = 1; i <= n + m; i++)
{
t[i].no = i;
}
sort(t + 1, t + n + m + 1, cmp2);
slove(1, n + m);
for (i = 1; i <= m; i++)
{
printf("%d\n", ans[i]);
}
return 0;
}
正解bitset:
#include<bitset>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 31
using namespace std;
struct Point
{
double x[4];
int no;
void read()
{
scanf("%lf%lf%lf%lf",x,x+1,x+2,x+3);
}
}a[N],b[N];
int C;
bitset<N>temp,ans[N];
bool cmp(Point a,Point b)
{
return a.x[C]<b.x[C];
}
int main()
{
int n,m,i,j,k;
scanf("%d",&n);
for(i=1;i<=n;i++)
a[i].read(),a[i].no=i;
scanf("%d",&m);
for(i=1;i<=m;i++)
b[i].read(),b[i].no=i;
for(C=0;C<4;C++)
{
sort(a+1,a+n+1,cmp);
sort(b+1,b+m+1,cmp);
temp=0,i=1;
for(j=1;j<=m;j++)
{
while(i<=n&&a[i].x[C]<=b[j].x[C])
temp[a[i++].no]=1;
if(!C)
ans[b[j].no]=temp;
else
ans[b[j].no]&=temp;
}
}
for(i=1;i<=m;i++)
printf("%d\n",ans[i].count());
return 0;
}
我选择弃疗,计算几何目前还是弱鸡,等学了半平面交有心情再搞搞(?)吧