【gdoi2018 day2】木板

题目大意:

随机、随机、随机

题解:

维护l,r分别表示每块木板向走向右第一个比它高的。

修改x,l,r无变化。

修改y

1.拔高:
按原来的l,r往左右跳,维护一下。

2.降低:
如果x-1的高度小于x,则从x-1开始,一直跳l,同时维护它们的r。

右边的同理。

查询:
结论是答案一定在x的r链和y的l链上,用个单调栈维护一下,复杂度为链长。

由于是随机数据,所以链长期望是log的,因此总复杂度为O(n log n)

我嫌麻烦,不是这么打的,暴力往左和往右移就过了,复杂度也许是O(n^2 / log n)?

Code:

#include
#define ll long long
#define fo(i, x, y) for(int i = x; i <= y; i ++)
#define fd(i, x, y) for(int i = x; i >= y; i --)
#define abs(a) ((a) > 0 ? (a) : -(a))
#define min(a, b) ((a) < (b) ? (a) : (b))
#define max(a, b) ((a) > (b) ? (a) : (b))
using namespace std;

const int N = 5e5 + 5;

int n, q, a[N], b[N], l[N], r[N], u[N], v[N];
int num, x, y, p;

int ql(int x) {
    int p = x;
    while(b[p] <= b[x]) p --;
    return p;
}

int qr(int x) {
    int p = x;
    while(b[p] <= b[x]) p ++;
    return p;
}

int main() {
    freopen("board.in", "r", stdin);
    freopen("board.out", "w", stdout);
    scanf("%d %d", &n, &q);
    fo(i, 1, n) scanf("%d", &a[i]);
    fo(i, 1, n) scanf("%d", &b[i]);
    b[0] = b[n + 1] = 2e9;
    fo(i, 1, n) l[i] = ql(i), r[i] = qr(i);
    fo(ii, 1, q) {
        scanf("%d %d %d", &num, &x, &y);
        if(num == 3) {
            a[x] = y;
        } else
        if(num == 2) {
            b[x] = y;
            l[x] = ql(x);
            r[x] = qr(x);
            fo(i, l[x] + 1, x - 1) r[i] = qr(i);
            fo(i, x + 1, r[x] - 1) l[i] = ql(i);
        } else {
            u[0] = v[0] = 0;
            p = x;
            while(p <= y) u[++ u[0]] = p, p = r[p];
            if(u[u[0]] > n) u[0] --;
            p = y;
            while(p >= x) v[++ v[0]] = p, p = l[p];
            if(v[v[0]] < 1) v[0] --;
            ll ans = 0;
            fo(i, 1, u[0]) fo(j, 1, v[0])
                ans = max(ans, (ll) min(b[u[i]], b[v[j]]) * abs(a[u[i]] - a[v[j]]));
            printf("%lld\n", ans);
        }
    }
}

你可能感兴趣的:(杂题)