其实这只是一道题的题解= =;
博主太弱不会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的(笑));
代码:
排序+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; }
我选择弃疗,计算几何目前还是弱鸡,等学了半平面交有心情再搞搞(?)吧
原文地址:http://blog.csdn.net/ww140142/article/details/47184335