首页 > 其他 > 详细

jzoj 6308. 中间值

时间:2019-08-18 18:28:01      阅读:101      评论:0      收藏:0      [点我收藏+]

Description

详见OJ

Solution

考场先想到\(O(nlog^2n)\)的线段树,发现过不了。于是开始“异想天开”。
最后神奇想到分块。
我们对于\(a[]\)维护一个\(to[i]\)
\(to[i]\)表示\(a[i]>=b[j]\)的最大的\(j\)
维护时用分块来标记防止修改的区间太大。
赛后同学说分块是\(O(m根号n)\)的,我才发现时间好像过不了。。。
但我好像没有一个点\(TLE\)。。。
不停改细节最后成功\(AC\)\(700+ms\)没有卡线。
分块打法好!

Code

(分块)

#include <cstdio>
#include <cmath>
#define N 500010
#define mem(x, a) memset(x, a, sizeof x)
#define fo(x, a, b) for (int x = a; x <= b; x++)
#define fd(x, a, b) for (int x = a; x >= b; x--)
using namespace std;
int n, m, a[N], b[N], to[N], now = 0;
int bl[N], val[N], st, zuo[N], you[N];
bool bz[N];

inline int read()
{
    int x = 0; char c = getchar();
    while (c < '0' || c > '9') c = getchar();
    while (c >= '0' && c <= '9') x = (x << 1) + (x << 3) + (c ^ 48), c = getchar();
    return x;
}

inline int max(int x, int y) {return x > y ? x : y;}

inline int solve(int x) {return bz[bl[x]] ? val[bl[x]] : to[x];}

void gave(int x)
{
    if (! bz[x]) return;
    fo(i, zuo[x], you[x]) to[i] = val[x];
    bz[x] = 0;
}

int main()
{
    freopen("median.in", "r", stdin);
    freopen("median.out", "w", stdout);
    n = read(), m = read(); st = sqrt(n);
    fo(i, 1, n)
    {
        a[i] = read();
        bl[i] = (i - 1) / st + 1;
        if (! zuo[bl[i]]) zuo[bl[i]] = i;
        you[bl[i]] = i;
    }
    fo(i, 1, n) b[i] = read();
    fo(i, 1, n)
    {
        while (now < n && a[i] >= b[now + 1]) now++;
        to[i] = now;
    }
    to[0] = 0, to[n + 1] = n;
    while (m--)
    {
        int opt = read();
        if (opt == 1)
        {
            int x = read(), y = read(), z = read();
            if (x == 0)
            {
                int l = solve(y - 1), r = solve(y + 1), mid;
                while (l <= r)
                {
                    mid = l + r >> 1;
                    if (z >= b[mid]) l = mid + 1;
                    else r = mid - 1;
                }
                a[y] = z;
                if (solve(y) != l - 1)
                    to[y] = l - 1, bz[bl[y]] = 0;
            }
            else
            {
                int l = 1, r = n, mid, le, ri;
                while (l <= r)
                {
                    mid = l + r >> 1;
                    if (a[mid] >= b[y - 1]) r = mid - 1;
                    else l = mid + 1;
                }
                le = r + 1;
                l = r, r = n;
                while (l <= r)
                {
                    mid = l + r >> 1;
                    if (a[mid] < b[y + 1]) l = mid + 1;
                    else r = mid - 1;
                }
                ri = l - 1;
                l = le, r = ri;
                while (l <= r)
                {
                    mid = l + r >> 1;
                    if (a[mid] >= z) r = mid - 1;
                    else l = mid + 1;
                }
                if (le <= r)
                {
                    if (bl[le] == bl[r])
                    {
                        gave(bl[le]);
                        fo(i, le, r) to[i] = y - 1;
                    }
                    else
                    {
                        fo(i, bl[le] + 1, bl[r] - 1)
                            bz[i] = 1, val[i] = y - 1;
                        gave(bl[le]);
                        fo(i, le, you[bl[le]]) to[i] = y - 1;
                        gave(bl[r]);
                        fo(i, zuo[bl[r]], r) to[i] = y - 1;
                    }
                }
                r++;
                if (r <= ri)
                {
                    if (bl[r] == bl[ri])
                    {
                        gave(bl[r]);
                        fo(i, r, ri) to[i] = y;
                    }
                    else
                    {
                        fo(i, bl[r] + 1, bl[ri] - 1)
                            bz[i] = 1, val[i] = y;
                        gave(bl[r]);
                        fo(i, r, you[bl[r]]) to[i] = y;
                        gave(bl[ri]);
                        fo(i, zuo[bl[ri]], ri) to[i] = y;
                    }
                }
                b[y] = z;
            }
        }
        else
        {
            int l1 = read(), r1 = read(), l2 = read(), r2 = read();
            int sum = (r1 - l1 + 1 + r2 - l2 + 1) / 2 + 1;
            if (a[r1] <= b[l2])
            {
                if (r1 - l1 + 1 >= sum) printf("%d\n", a[l1 + sum - 1]);
                else printf("%d\n", b[l2 + sum - (r1 - l1 + 1) - 1]);
            }
            else if (a[l1] >= b[r2])
            {
                if (r2 - l2 + 1 >= sum) printf("%d\n", b[l2 + sum - 1]);
                else printf("%d\n", a[l1 + sum - (r2 - l2 + 1) - 1]);
            }
            else
            {
                int l = l1, r = r1, mid, num;
                while (l <= r)
                {
                    mid = l + r >> 1;
                    num = mid - l1 + 1;
                    if (solve(mid) > r2) num += r2 - l2 + 1;
                    else if (solve(mid) >= l2) num += solve(mid) - l2 + 1;
                    if (num == sum) {r = mid - 1; break;}
                    else if (num >= sum) r = mid - 1;
                    else l = mid + 1;
                }
                r++;
                num = r - l1 + 1;
                if (solve(r) > r2) num += r2 - l2 + 1;
                else if (solve(r) >= l2) num += solve(r) - l2 + 1;
                if (r <= r1 && num == sum) printf("%d\n", a[r]);
                else printf("%d\n", b[l2 + sum - (r - l1 + 1)]);
            }
        }
    }
    return 0;
}

不过,听完讲后,发现这题分治做起来好容易啊。

jzoj 6308. 中间值

原文:https://www.cnblogs.com/jz929/p/11372844.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!