JZOJ 5390 逗气

传送门
思路

唉,我太弱了,这么之前的题,到现在才会做,唉,我太弱啦!

将逗气聚集点和聚逗阵按位置排序。对于每个聚逗阵,我们把它左边和右边的逗气聚集点分开考虑,且从左向右考虑。下面我们只讨论逗气聚集点在聚逗阵左边的情况,右边的情况与之相似。

设聚逗阵 j 在聚逗阵 k 的右边( a j > a k ),它们都在逗气聚集点 i 的左边。若 j k 优,那么我们有:

b j ( c i a j ) × d i > b k ( c i a k ) × d i

整理得:

b j b k a j a k > d i

注意分母的符号一定是正号,因此可以除过来。

根据斜率优化的理论,设不等式左边为 s l o p e ( j , k ) ( j > k ) ,如果有 s l o p e ( j , k ) > s l o p e ( k , l ) ,那么 k 永远不会是最优的。所以用一个单调栈维护,寻找决策点在凸包上二分找切点即可。

实际操作上,我习惯写倍增,并且实际找的东西并不是切点(切点只是为了方便理解),而是第一个不满足不等式的点或者栈顶。

参考代码
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <cassert>
#include <cctype>
#include <climits>
#include <ctime>
#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
#include <stack>
#include <queue>
#include <deque>
#include <map>
#include <set>
#include <bitset>
#include <list>
#include <functional>
typedef long long LL;
typedef unsigned long long ULL;
using std::cin;
using std::cout;
using std::endl;
typedef LL INT_PUT;
INT_PUT readIn()
{
    INT_PUT a = 0; bool positive = true;
    char ch = getchar();
    while (!(ch == '-' || std::isdigit(ch))) ch = getchar();
    if (ch == '-') { positive = false; ch = getchar(); }
    while (std::isdigit(ch)) { a = a * 10 - (ch - '0'); ch = getchar(); }
    return positive ? -a : a;
}
void printOut(INT_PUT x)
{
    char buffer[20]; int length = 0;
    if (x < 0) putchar('-'); else x = -x;
    do buffer[length++] = -(x % 10) + '0'; while (x /= 10);
    do putchar(buffer[--length]); while (length);
    putchar('\n');
}

const int maxn = int(2e5) + 5;
int n, m;
struct TypeA
{
    int a, b;
    void read()
    {
        a = readIn();
        b = readIn();
    }
    bool operator<(const TypeA& y) const
    {
        return a < y.a;
    }
} tas[maxn];
struct TypeB
{
    int c, d;
    void read()
    {
        c = readIn();
        d = readIn();
    }
    bool operator<(const TypeB& y) const
    {
        return c < y.c;
    }
} tbs[maxn];
int idx[maxn];
bool comp(const int& x, const int& y)
{
    return tbs[x] < tbs[y];
}

int stack[maxn];
int top;
LL f[maxn];

double slope(int j, int k)
{
    return (double)(tas[j].b - tas[k].b) / (tas[j].a - tas[k].a);
}
LL DP1(int i, int j)
{
    return std::max(LL(0), tas[j].b - (LL)(tbs[i].c - tas[j].a) * tbs[i].d);
}
LL DP2(int i, int j)
{
    return std::max(LL(0), tas[j].b - (LL)(tas[j].a - tbs[i].c) * tbs[i].d);
}

void run()
{
    n = readIn();
    m = readIn();
    for (int i = 1; i <= n; i++)
        tas[i].read();
    for (int i = 1; i <= m; i++)
        tbs[i].read();
    for (int i = 1; i <= m; i++)
        idx[i] = i;
    std::sort(tas + 1, tas + 1 + n);
    std::sort(idx + 1, idx + 1 + m, comp);
    for (int i = 1; i <= m; i++)
        f[i] = LLONG_MIN;

    int cnt;

    cnt = 1;
    top = 0;
    for (int i = 1; i <= m; i++)
    {
        const TypeB& tb = tbs[idx[i]];
        for (; cnt <= n && tas[cnt].a <= tb.c; cnt++)
        {
            const TypeA& ta = tas[cnt];
            while (top > 1 && slope(cnt, stack[top - 1]) >
                slope(stack[top - 1], stack[top - 2]))
                top--;
            stack[top++] = cnt;
        }
        if (top)
        {
            int t = 0;
            int k = 0;
            while (1 << k < (top - 1)) k++;
            for (int j = k; ~j; j--) if (t + (1 << j) < top)
            {
                if (slope(stack[t + (1 << j)], stack[t + (1 << j) - 1]) > -tb.d)
                    t += 1 << j;
            }
            f[idx[i]] = std::max(f[idx[i]], DP1(idx[i], stack[t]));
        }
    }

    cnt = n;
    top = 0;
    for (int i = m; i; i--)
    {
        const TypeB& tb = tbs[idx[i]];
        for (; cnt && tas[cnt].a >= tb.c; cnt--)
        {
            const TypeA& ta = tas[cnt];
            while (top > 1 && slope(cnt, stack[top - 1]) <
                slope(stack[top - 1], stack[top - 2]))
                top--;
            stack[top++] = cnt;
        }
        if (top)
        {
            int t = 0;
            int k = 0;
            while (1 << k < (top - 1)) k++;
            for (int j = k; ~j; j--) if (t + (1 << j) < top)
            {
                if (slope(stack[t + (1 << j)], stack[t + (1 << j) - 1]) < tb.d)
                    t += 1 << j;
            }
            f[idx[i]] = std::max(f[idx[i]], DP2(idx[i], stack[t]));
        }
    }

    for (int i = 1; i <= m; i++)
        printOut(f[i]);
}

int main()
{
#ifndef LOCAL
    freopen("gas.in", "r", stdin);
    freopen("gas.out", "w", stdout);
#endif
    run();
    return 0;
}

猜你喜欢

转载自blog.csdn.net/lycheng1215/article/details/80372812