BZOJ 3833 [POI 2014] Solar Lamps 解题报告

来源:互联网 发布:谷歌浏览器禁止js 编辑:程序博客网 时间:2024/06/06 01:30

相信大家都是看了题才来看题解的

所以我就不发题面了=_=

不如当一个萌萌哒链接菌吧=_=

毕竟我懒=_=

题目传送门

Solution

卧槽。【总领全文,奠定感情基调】

首先我们可以进行坐标变换。

如果两个向量构成一组基底,

我们可以把平面内每个的坐标 (xi,yi) 变换成 (ai,bi)

使得:

ai×x1+bi×x2=xi

ai×y1+bi×y2=yi

于是我们可以求得 aibi

ai=xi×y2yi×x2x1×y2x2×y1

bi=xi×y1yi×x1x1×y2x2×y1

然后我们发现这些坐标都是分数,

而且最重要的是:分母都是一样的。

于是我们可以令所有的坐标都乘以这个分母(要保证乘的是正的数字)。

于是我们就可以离散化这些点的坐标,使得坐标范围变成一个(1,1)(n,m)的矩阵。

于是再给点以 bi 为第一关键字,ai 为第二关键字排序,

并按照这个顺序处理那些点。

这样我们后面的点的 b 坐标就一定大于等于前面的点的 b 坐标,

就可以不用管这一维了,只用管 a 坐标了。

于是我们假设处理到第 i 个灯泡,

t 为以 (1,1) 为左下角,(ai,bi) 为右上角的矩阵中 Ans[]K[i] 小的值。

那么 Ans[i]=min(i,t)

特别的,如果那个矩阵中没有K[i]多灯泡,Ans[i]=i

于是怎么维护呢?

【插入操作】

我们以时间为 Ans[] 第一关键字建立线段树,套上以 a 坐标为第二关键字的平衡树。

每次插入都会在 O(logn) 个线段树结点所套的平衡树中进行时间为 O(logn) 的插入操作,

于是插入操作的时间复杂度是 O(log2n) 的。

【查询操作】

怎么查询以 (1,1) 为左下角,(ai,bi) 为右上角的矩阵中 Ans[]K[i] 小的值呢?

我们可以二分答案。

具体做法就是从线段树根结点开始,先看左儿子所套的平衡树里边 a 坐标小于等于 ai 的结点个数。

设有 u 个,那么就说明 Ans[][l,mid] 区间内的,

并且在以 (1,1) 为左下角,(ai,bi) 为右上角的矩阵中的点有 u 个。

如果 uK[i],说明答案应该在 [l,mid] 之间,然后递归处理。

否则答案就应该在 [mid+1,r] 之间,然后递归处理。

直到 l=r 的时候,便可确定 Ans[i]=min(i,l)

然后我们可以加上一个小优化:

如果递归处理到 [l,r] 的区间,并且有 li

那么直接返回 i

因为 Ans[i]=min(i,l)

如果可能的最小值都不比 i 小了,那么就没有做下去的必要了。

查询操作中,我们要访问 O(logn) 个线段树结点,在每个线段树节点中,都要 O(logn) 地查找相关点的个数。

所以查询操作的时间复杂度也是 O(log2n) 的。

然后有 O(n) 个灯泡,所以总时间复杂度是 O(nlog2n) 的。

每个灯泡的信息会被插入到 O(logn) 个线段树所套的平衡树里,

所以空间复杂度是 O(nlogn) 的。

如果写矩形树(二维线段树)的话空间复杂度就是 O(nlog2n) 的,承受不了。

所以才要写这种蛋疼的东西。。。

卧槽。【承上启下,推动情节发展】

等等。

我们好像忽略了一点:

如果灯的照射范围是一条线该怎么办。。。

啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊。。。

其实也比较好处理。

我们把另一个向量弄成垂直于当前的这条向量。

可以令 :x2=y1y2=x1

然后也可以求出点的 a 坐标和 b 坐标,

只不过在查询的时候,我们找的就不是矩阵中点的个数,

而是某一条线段里边的点的个数了。

稍微处理一下就可以了。。。=_=

具体实现可以看我的代码。

卧槽。【总结全文,升华文章主旨】

毕竟 Gromah 太弱,只会做水题。

#include <cmath>#include <cstdio>#include <vector>#include <cstdlib>#include <cstring>#include <iostream>#include <algorithm>using namespace std;typedef long long LL;#define N 200000 + 5#define M 524288 + 5#define SIZE 5000000 + 5#define ls(x) x << 1#define rs(x) x << 1 | 1int n, tot, Ord[N], Root[M], Ans[N], K[N];LL x_1, y_1, x_2, y_2, X[N], Y[N], _X[N], _Y[N];struct Data{    int l, r, fa, size, num, fix;}h[SIZE];inline void update(int x){    h[x].size = h[h[x].l].size + h[h[x].r].size + h[x].fix;}inline void zig(int x){    int y = h[x].fa, z = h[y].fa;    if (y == h[z].l) h[z].l = x;    if (y == h[z].r) h[z].r = x;    h[x].fa = z, h[y].fa = x;    h[y].l = h[x].r, h[h[x].r].fa = y, h[x].r = y;    update(y), update(x);}inline void zag(int x){    int y = h[x].fa, z = h[y].fa;    if (y == h[z].l) h[z].l = x;    if (y == h[z].r) h[z].r = x;    h[x].fa = z, h[y].fa = x;    h[y].r = h[x].l, h[h[x].l].fa = y, h[x].l = y;    update(y), update(x);}inline void Splay(int &root, int x){    while (h[x].fa)    {        int y = h[x].fa, z = h[y].fa;        if (x == h[y].l)        {            if (y == h[z].l) zig(y);            zig(x);        }        else        {            if (y == h[z].r) zag(y);            zag(x);        }    }    root = x;}inline void Insert(int &root, int u){    if (!root)    {        root = ++ tot;        h[tot].size = h[tot].fix = 1, h[tot].num = u;        return ;    }    int z, p = root;    while (p)    {        z = p;        h[z].size ++;        if (u == h[z].num)        {            h[z].fix ++;            return ;        }        if (u > h[z].num)            p = h[z].r;        else p = h[z].l;    }    h[++ tot].fix = 1;    h[tot].size = 1;    h[tot].num = u;    h[tot].fa = z;    if (u > h[z].num)        h[z].r = tot;    else h[z].l = tot;    Splay(root, tot);}inline int Find(int x, int k, bool op){    int res = 0;    while (1)    {        if (!x)        {            if (op) return 0;            break ;        }        if (k == h[x].num)        {            if (op) return h[x].fix;            res += h[h[x].l].size + h[x].fix;            break ;        }        else if (k > h[x].num)        {            res += h[h[x].l].size + h[x].fix;            x = h[x].r;        }        else x = h[x].l;    }    return res;}inline int Query(int x, int l, int r, int k, int lim, int Lim, bool op){    if (l >= Lim) return Lim;    if (l == r) return l;    int mid = l + r >> 1;    int t = Find(Root[ls(x)], lim, op);    if (k <= t)        return Query(ls(x), l, mid, k, lim, Lim, op);    else return Query(rs(x), mid + 1, r, k - t, lim, Lim, op);}inline void Modify(int x, int l, int r, int t, int k){    Insert(Root[x], k);    if (l == r) return ;    int mid = l + r >> 1;    if (t <= mid)        Modify(ls(x), l, mid, t, k);    else Modify(rs(x), mid + 1, r, t, k);}inline int getint(){    char ch = '\n';    for (; ch != '-' && (ch > '9' || ch < '0'); ch = getchar()) ;    int f = ch == '-' ? -1 : 1;    int res = ch == '-' ? 0 : ch - '0';    for (ch = getchar(); ch >= '0' && ch <= '9'; ch = getchar())        res = (res << 3) + (res << 1) + ch - '0';    return res * f;}inline bool cmp(int u, int v){    return X[u] < X[v] || (X[u] == X[v] && Y[u] < Y[v]);}inline void Solve(bool op){    if (op) x_2 = -y_1, y_2 = x_1;    int f = (x_2 * y_1 - x_1 * y_2 > 0) ? 1 : -1;    for (int i = 1; i <= n; i ++)    {        LL u = getint(), v = getint();        _X[i] = X[i] = (x_2 * v - y_2 * u) * f;        _Y[i] = Y[i] = (y_1 * u - x_1 * v) * f;    }    sort(_X + 1, _X + n + 1);    sort(_Y + 1, _Y + n + 1);    int sx = unique(_X + 1, _X + n + 1) - _X;    int sy = unique(_Y + 1, _Y + n + 1) - _Y;    for (int i = 1; i <= n; i ++)    {        int u = lower_bound(_X + 1, _X + sx, X[i]) - _X;        int v = lower_bound(_Y + 1, _Y + sy, Y[i]) - _Y;        X[i] = u, Y[i] = v;        Ord[i] = i, K[i] = getint();    }    sort(Ord + 1, Ord + n + 1, cmp);    for (int i = 1; i <= n; i ++)    {        int _i = Ord[i];        if (Find(Root[1], Y[_i], op) < K[_i]) Ans[_i] = _i;            else Ans[_i] = Query(1, 1, n, K[_i], Y[_i], _i, op);        Modify(1, 1, n, Ans[_i], Y[_i]);    }}int main(){    #ifndef ONLINE_JUDGE        freopen("3833.in", "r", stdin);        freopen("3833.out", "w", stdout);    #endif    n = getint();    x_1 = getint(), y_1 = getint();    x_2 = getint(), y_2 = getint();    Solve(x_1 * y_2 == x_2 * y_1);    for (int i = 1; i <= n; i ++)        printf("%d%c", Ans[i], " \n"[i == n]);    return 0;}
0 0
原创粉丝点击