[BZOJ3337] ORZJRY I --块状链表大毒瘤

link

题目大意:维护一个序列

支持:

1.单点插入
2.单点删除
3.区间翻转
4.区间旋转
5.区间加
6.区间赋值
7.询问区间和
8.询问区间极差
9.询问区间与给定某个数差值绝对值的最小值
10.询问区间第k小
11.询问区间某个数排名

艹 11个操作 太毒瘤了 写了一下午+晚上一节课(包含中途透彻时间

这么多操作各种平衡树都上不了了,就块状链表

操作1:找到位置,把一个块拆分,转化为在快末尾插入
操作2:拆分块,转化为在块末尾删除
操作3:把翻转的区间拎出来,每个区间打个翻转标记,然后指针瞎指下
操作4:把旋转的区间拎出来,每个区间打个旋转标记
操作5:把区间拎出来打加法标记
操作6:把区间拎出来打赋值标记
操作7:把区间拎出来维护区间sum直接求和
操作8:每个块维护s数组代表块内元素排序好的结果,把区间拎出来后直接询问,每个块返回s[0]和s[size-1]
操作9:每个块s数组里lower_bound和upper_bound
操作10:二分,转化为操作11
操作11:每个块s数组里lower_bound

细节:
0.每次操作后遍历整个链表,检查两个相邻块大小太小就要合并

每个块维护a[],s[],sz,sum,三个标记,链表指针

区间赋值标记优先级比另外两个高,另外两个可以共存

需要对某个块进行大修改(分裂/合并)等之前要先清除标记,区间查询内不能清除标记

块尾insert和delete维护s数组要用插入排序及其逆操作

。。。忘了还有啥要注意的了

#include <cstdio>
#include <cmath>
#include <vector>
#include <algorithm>
using namespace std;

struct fuck
{
    int a[1000], s[1000]; //原序列/有序序列
    int sz, chenge_flag, add_flag;
    //chenge_flag存在时忽视add_flag和rev_flag
    //不存在时另外两个标记互相不影响
    long long sum; //和
    bool rev_flag; //翻转标记
    fuck *nex; //下个指针
    
    fuck()
    {
        sz = 0;
        sum = 0;
        nex = 0;
        chenge_flag = -1;
        add_flag = 0;
        rev_flag = false;
    }
    void access()
    {
        if (chenge_flag != -1)
        {
            for (int i = 0; i < sz; i++) a[i] = s[i] = chenge_flag;
            sum = sz * (long long)chenge_flag;
            chenge_flag = -1;
        }
        else
        {
            if (add_flag != 0)
            {
                for (int i = 0; i < sz; i++) a[i] += add_flag, s[i] += add_flag;
                sum += sz * (long long)add_flag;
                add_flag = 0;
            }
            if (rev_flag != 0) {reverse(a, a + sz); rev_flag ^= 1; }
        }
    }
    void gc(int x)
    {
        add_flag = rev_flag = 0;
        chenge_flag = x;
    }
    void ga(int x)
    {
        if (chenge_flag == -1) add_flag += x;
        else chenge_flag += x;
    }
    void gr()
    {
        if (chenge_flag == -1) rev_flag ^= 1;
    }
    void push_back(int x)
    {
        access();
        //维护s
        if (sz == 0 || x >= s[sz - 1]) s[sz] = x;
        else for (int i = sz - 1; i >= 0; i--)
        {
            s[i + 1] = s[i];
            if (i == 0 || s[i - 1] <= x) { s[i] = x; break; }
        }
        //维护sum和a
        sum += (a[sz++] = x);
    }
    void delete_back()
    {
        access();
        sum -= a[sz - 1];
        for (int i = 0 ;i < sz; i++)
        {
            if (s[i] == a[sz - 1])
            {
                for (int j = i + 1; j < sz; j++)
                    s[j - 1] = s[j];
            }
        }
        sz--;
    }
    int qmax()
    {
        if (sz == 0) return 0;
        else if (chenge_flag != -1) return chenge_flag;
        else return s[sz - 1] + add_flag;
    }
    int qmin()
    {
        if (sz == 0) return 0x7fffffff;
        else if (chenge_flag != -1) return chenge_flag;
        else return s[0] + add_flag;
    }
    long long qsum()
    {
        if (chenge_flag != -1) return chenge_flag * (long long)sz;
        else return sum + add_flag * (long long)sz;
    }
    int query(int val)
    {
        if (chenge_flag != -1) return chenge_flag < val ? sz : 0;
        val -= add_flag;
        return lower_bound(s, s + sz, val) - s;
    }
    int mindis(int val)
    {
        if (sz == 0) return 0x7fffffff;
        if (chenge_flag != -1) return abs(chenge_flag - val);
        val -= add_flag;
        int pos0 = lower_bound(s, s + sz, val) - s;
        if (pos0 < sz && s[pos0] == val) return 0; else pos0--;
        int pos1 = upper_bound(s, s + sz, val) - s;
        if (pos0 >= 0 && pos0 < sz) pos0 = val - s[pos0];
        else pos0 = 0x7fffffff;
        if (pos1 >= 0 && pos1 < sz) pos1 = s[pos1] - val;
        else pos1 = 0x7fffffff;
        // printf("id = %p, [%d, %d
        return min(pos0, pos1);
    }
    void print(bool p = 0)const
    {
        printf("------------\n某一块%p\n大小%d,和为%lld\nnex=%p\n", this, sz, sum, nex);
        printf("c=%d, a=%d, r=%d\n", chenge_flag, add_flag, rev_flag);
        for (int i = 0; i < sz; i++) { printf("%d ", a[i]);} printf("\n");
        for (int i = 0; i < sz; i++) { printf("%d ", s[i]);} printf("\n");
        if (p && nex != 0) nex->print(p); //输出下一页
    }
};

int n, m, init[100010];
int blocksz, cur;
fuck *start;

fuck *newnode() { return new fuck; }
void delnode(fuck *x) { delete x; }

fuck *split(fuck *x, int pos) //x保留pos个元素,在x后面新建一个节点
{
    x->access();
    if (pos > x->sz) { printf("fuck!\n"); return 0; }
    fuck *res = newnode();
    //-----维护res
    for (int i = pos; i < x->sz; i++)
        res->sum += (res->a[i - pos] = res->s[i - pos] = x->a[i]);
    res->sz = x->sz - pos;
    sort(res->s, res->s + res->sz);
    res->nex = x->nex;
    //-----维护x
    x->sz = pos; x->sum = 0;
    for (int i = 0; i < pos; i++) x->sum += (x->s[i] = x->a[i]);
    sort(x->s, x->s + pos);
    x->nex = res;
    return res;
}

void merge(fuck *x)
{
    x->access();
    x->nex->access();
    fuck *p = x->nex;
    for (int i = 0; i < p->sz; i++)
        x->sum += (x->a[x->sz + i] = p->a[i]);
    x->sz += p->sz;
    x->nex = p->nex;
    for (int i = 0; i < x->sz; i++) x->s[i] = x->a[i];
    sort(x->s, x->s + x->sz);
    delnode(p);
}

void maintain()
{
    for (fuck *p = start; p != 0; p = p->nex)
    {
        while (p->nex != 0 && p->sz + p->nex->sz <= blocksz)
            merge(p);
    }
}

void get(int l, int r, fuck* &lp, fuck* &rp)
{
    lp = start;
    while (lp != 0)
    {
        if (l <= lp->sz) break;
        l -= lp->sz;
        lp = lp->nex;
    }
    if (l != 1)
        split(lp, l - 1), lp = lp->nex;
    rp = start;
    while (rp != 0)
    {
        if (r <= rp->sz) break;
        r -= rp->sz;
        rp = rp->nex;
    }
    if (r != rp->sz)
        split(rp, r);
}

void del(fuck *z)
{
    if (z->nex) del(z->nex);
    delete z;
}

void chkmax(int &a, int b) { if (a < b) a = b; }
void chkmin(int &a, int b) { if (a > b) a = b; }

int main()
{
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) scanf("%d", &init[i]);
    scanf("%d", &m);
    blocksz = sqrt(n + m / 5) * 3 / 4;
    fuck *now = start = newnode();
    for (int i = 1; i <= n; i++)
    {
        now->push_back(init[i]);
        if (i % blocksz == 0 && i != n)
        {
            fuck *p = newnode();
            now->nex = p;
            now = p;
        }
    }
    for (int opd, x, y, k, val, i = 1; i <= m; i++)
    {
        scanf("%d", &opd);
        switch (opd)
        {
            case 1:
            {
                scanf("%d%d", &x, &val);
                fuck *p = start;
                while (p != 0)
                {
                    if (x <= p->sz) break;
                    x -= p->sz;
                    p = p->nex;
                }
                //从0开始计数,放在p的第x个位置,也就是说p前面有x个数
                split(p, x);
                p->push_back(val);
                maintain();
                break;
            }
            case 2:
            {
                scanf("%d", &x);
                fuck *p = start;
                while (p != 0)
                {
                    if (x <= p->sz) break;
                    x -= p->sz;
                    p = p->nex;
                }
                //删除第x个数,所以前面需要x个数
                split(p, x);
                p->delete_back();
                maintain();
                break;
            }
            case 3:
            {
                scanf("%d%d", &x, &y);
                fuck *l, *r;
                get(x, y, l, r), r = r->nex;
                vector<fuck*> li;
                split(l, 0);
                for (fuck *p = l->nex; p != r; p = p->nex)
                    li.push_back(p), p->gr();
                l->nex = li[li.size() - 1];
                for (int i = li.size() - 1; i > 0; i--)
                    li[i]->nex = li[i - 1];
                li[0]->nex = r;
                maintain();
                break;
            }
            case 4:
            {
                scanf("%d%d%d", &x, &y, &k);
                fuck *l1, *r1, *l2, *r2;
                get(x, y - k, l1, r1);
                get(y - k + 1, y, l2, r2);
                if (start == l1) start = l2;
                else
                {
                    fuck *p = start;
                    while (p->nex != l1) p = p->nex;
                    p->nex = l2;
                }
                r1->nex = r2->nex;
                r2->nex = l1;
                maintain();
                break;
            }
            case 5:
            {
                scanf("%d%d%d", &x, &y, &val);
                fuck *l, *r;
                get(x, y, l, r), r = r->nex;
                for (fuck *p = l; p != r; p = p->nex)
                    p->ga(val);
                maintain();
                break;
            }
            case 6:
            {
                scanf("%d%d%d", &x, &y, &val);
                fuck *l, *r;
                get(x, y, l, r), r = r->nex;
                for (fuck *p = l; p != r; p = p->nex)
                    p->gc(val);
                maintain();
                break;
            }
            case 7:
            {
                scanf("%d%d", &x, &y);
                fuck *l, *r;
                get(x, y, l, r), r = r->nex;
                long long ans = 0;
                for (fuck *p = l; p != r; p = p->nex)
                    ans += p->qsum();
                printf("%lld\n", ans);
                maintain();
                break;
            }
            case 8:
            {
                scanf("%d%d", &x, &y);
                fuck *l, *r;
                get(x, y, l, r), r = r->nex;
                int maxn = 0, minn = 0x7fffffff;
                for (fuck *p = l; p != r; p = p->nex)
                    chkmax(maxn, p->qmax()), chkmin(minn, p->qmin());
                printf("%d\n", maxn - minn);
                maintain();
                break;
            }
            case 9:
            {
                scanf("%d%d%d", &x, &y, &val);
                fuck *l, *r;
                get(x, y, l, r), r = r->nex;
                int res = 0x7fffffff;
                for (fuck *p = l; p != r; p = p->nex)
                    chkmin(res, p->mindis(val));
                printf("%d\n", res);
                maintain();
                break;
            }
            case 10:
            {
                scanf("%d%d%d", &x, &y, &k);
                fuck *l, *r;
                get(x, y, l, r), r = r->nex;
                long long cl = 1, cr = 0x7fffffff;
                while (cl < cr)
                {
                    long long mid = (cl + cr) / 2;
                    int tot = 0;
                    for (fuck *p = l; p != r; p = p->nex)
                        tot += p->query(mid);
                    if (tot >= k) cr = mid;
                    else cl = mid + 1;
                }
                printf("%lld\n", cl - 1);
                maintain();
                break;
            }
            case 11:
            {
                scanf("%d%d%d", &x, &y, &val);
                fuck *l, *r;
                get(x, y, l, r), r = r->nex;
                int ans = 0;
                for (fuck *p = l; p != r; p = p->nex)
                    ans += p->query(val);
                printf("%d\n", ans);
                maintain();
                break;
            }
        }
    }
    del(start);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/oier/p/10366764.html
I
今日推荐