jzoj 6308. 中间值

Posted jz929

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了jzoj 6308. 中间值相关的知识,希望对你有一定的参考价值。

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. 中间值的主要内容,如果未能解决你的问题,请参考以下文章

jzoj6438

Visual Studio 警告 C6308 存在于缩小的动态数组中

JZOJ4645基因改造计划

bzoj 2785 jzoj 2755 2012东莞市选树的计数(计数+dp):

7.10 计算中间值

7.10 计算中间值