省队集训 Day6 序列

【题目大意】

给出$n$个数的序列$a_1, a_2, ..., a_n$,有$m$次操作,为下面三种:

$A~l~r~d$:区间$[l,r]$,全部加$d$。

$M~l~r~d$:区间$[l,r]$,对$d$取max。

$Q~x$:询问$a_x$的值。

对于30%的数据,$n, m\leq 10^4$;

对于60%的数据,保证数据随机;

对于100%的数据,满足$n, m \leq 10^5$,所有数的绝对值不超过$2^{31} - 1$。保证也是随机的。

【题解】

显然正解是吉司机线段树,我不会,那怎么办?分块!!!

对于100%的数据的那个性质我是拿数据后才知道的。

考场写了$O(n * (n/B) * logB)$的常数大的跟*一样的分块做法,其中$B = 32$,理论上$B = 128$左右比较优,可能是我常数太大了只能开32。。。

由于数据随机(迷),就过了……

具体是这样的,每个操作如果涉及部分块,直接暴力重构。

每个块内排序后,发现操作2相当于找一段前缀,改成$d$,然后将这些数的次数全部+1,这个可以方便用线段树维护,找的话线段树上二分即可。

操作1的话相当于块全局加,然后这些块的次数全部+1(需要特判$d=0$),可以记录一个全局标记来做。

然后就很方便维护信息了(吧),为了线段树上二分可能需要记录一个最小值。

然后调调边界啊,开开longlong啊,卡了卡常就过了。。

# include <stdio.h>
# include <assert.h>
# include <string.h>
# include <iostream>
# include <algorithm>
# define getchar getchar_unlocked

using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;

# ifdef WIN32
# define LLFORMAT "%I64d"
# else
# define LLFORMAT "%lld"
# endif

# define beg BEG
# define end END

const int N = 1e5 + 10, B = 3205, SN = 128 + 5;
const ll inf = 1e17;

inline int getint() {
    int x = 0, f = 1; char ch = getchar();
    while(!isdigit(ch)) {
        if(ch == ‘-‘) f = 0;
        ch = getchar();
    }
    while(isdigit(ch)) x = (x<<3) + (x<<1) + ch - ‘0‘, ch = getchar();
    return f ? x : -x;
}

int n, m, beg[B], end[B], len[B], bl[N], id[B][33];

struct pa {
    ll a; int t;
    pa() {}
    pa(ll a, int t) : a(a), t(t) {}
    inline friend bool operator < (pa a, pa b) {
        return a.a < b.a;
    }
    inline friend pa operator + (pa a, pa b) {
        return pa(min(a.a, b.a), 0);
    }
}p[N];

pa g[B]; int gn = 0;
ll add[B]; int addt[B];
struct SMT {
    // 区间覆盖,对于a做,区间加法,对于t做
    pa w[SN]; int tag[SN]; ll cov[SN]; bool hc[SN];
    # define ls (x<<1)
    # define rs (x<<1|1)
    inline void up(int x) {
        w[x] = w[ls] + w[rs];
    }
    inline void pushtag(int x, int tg) {
        tag[x] += tg; w[x].t += tg;
    }
    inline void pushcov(int x, ll c) {
        w[x].a = c; cov[x] = c; hc[x] = 1;
    }
    inline void down(int x) {
        if(hc[x]) {
            pushcov(ls, cov[x]); pushcov(rs, cov[x]);
            hc[x] = 0; cov[x] = 0;
        }
        if(tag[x]) {
            pushtag(ls, tag[x]); pushtag(rs, tag[x]);
            tag[x] = 0;
        }
    }
    inline void build(int x, int l, int r) {
        tag[x] = cov[x] = 0; hc[x] = 0;
        if(l == r) {
            w[x] = g[l];
            return ;
        }
        int mid = l+r>>1;
        build(ls, l, mid); build(rs, mid+1, r);
        up(x);
    }
    inline void cover(int x, int l, int r, int L, int R, ll p) {
        if(L <= l && r <= R) {
            pushcov(x, p);
            pushtag(x, 1);
            return ;
        }
        down(x);
        int mid = l+r>>1;
        if(L <= mid) cover(ls, l, mid, L, R, p);
        if(R > mid) cover(rs, mid+1, r, L, R, p);
        up(x);
    }
    inline void gans(int x, int l, int r) {
        if(l == r) {
            g[++gn] = w[x];
            return ;
        }
        down(x);
        int mid = l+r>>1;
        gans(ls, l, mid); gans(rs, mid+1, r);
    }
    inline pa gs(int x, int l, int r, int ps) {
//        cerr << x << ‘ ‘ << w[x].a << ‘ ‘ << w[x].t << endl;
        if(l == r) return w[x];
        down(x);
        int mid = l+r>>1;
        if(ps <= mid) return gs(ls, l, mid, ps);
        else return gs(rs, mid+1, r, ps);
    }
    // find the last number that < p
    inline int find(int x, int l, int r, ll p) {
        if(l == r) return l;
        down(x);
        int mid = l+r>>1;
        if(w[rs].a < p) return find(rs, mid+1, r, p);
        else return find(ls, l, mid, p);
    }

    inline void debug(int x, int l, int r) {
        printf("x = %d, min = " LLFORMAT "\n", x, w[x].a);
        if(l == r) {
            printf("  times = %d\n", w[x].t);
            return ;
        }
        int mid = l+r>>1;
        debug(ls, l, mid);
        debug(rs, mid+1, r);
    }
    # undef ls
    # undef rs
}T[B];

int tid[B];
inline bool cmp(int x, int y) {
    return p[x] < p[y];
}

namespace prepare {
    inline void deal(int x) {
        register int *pid = id[x], Len; Len = len[x] = end[x] - beg[x] + 1;
        for (register int i=1; i<=Len; ++i) tid[i] = beg[x] + i - 1;
        sort(tid+1, tid+Len+1, cmp);
        for (register int i=1; i<=Len; ++i) g[i] = p[tid[i]];
        T[x].build(1, 1, Len);
        for (register int i=1; i<=Len; ++i) pid[i] = tid[i];
    }
}

namespace option1 {
    inline void deal(int x, int l, int r, int c) {
        register int *pid = id[x], Len = len[x];
        gn = 0, T[x].gans(1, 1, Len);
        for (register int i=1; i<=Len; ++i) p[pid[i]] = g[i], tid[i] = beg[x] + i - 1;
        for (register int i=beg[x]; i<=end[x]; ++i) p[i].a += add[x], p[i].t += addt[x];
        add[x] = 0; addt[x] = 0;
        for (register int i=l; i<=r; ++i) p[i].a += c, p[i].t ++;
        sort(tid+1, tid+Len+1, cmp);
        for (register int i=1; i<=Len; ++i) g[i] = p[tid[i]];
        T[x].build(1, 1, Len);
        for (register int i=1; i<=Len; ++i) pid[i] = tid[i];
    }
    inline void deal(int x, int c) {
        add[x] += c; addt[x] ++;
    }
    inline void main(int l, int r, int c) {
        register int L = bl[l], R = bl[r];
        if(L == R) deal(L, l, r, c);
        else {
            deal(L, l, end[L], c);
            deal(R, beg[R], r, c);
            for (register int i=L+1; i<R; ++i) deal(i, c);
        }
    }
}

namespace option2 {
    inline void deal(int x, int l, int r, int c) {
        register int *pid = id[x], Len = len[x];
        gn = 0, T[x].gans(1, 1, Len);
        for (register int i=1; i<=Len; ++i) p[pid[i]] = g[i], tid[i] = beg[x] + i - 1;
        for (register int i=beg[x]; i<=end[x]; ++i) p[i].a += add[x], p[i].t += addt[x];
        add[x] = 0; addt[x] = 0;
        for (register int i=l; i<=r; ++i)
            if(p[i].a < c) p[i].a = c, p[i].t ++;
        sort(tid+1, tid+Len+1, cmp);
        for (register int i=1; i<=Len; ++i) g[i] = p[tid[i]];
//        for (int i=1; i<=len[x]; ++i) cerr << g[i].a << ‘ ‘ << g[i].t << " ====\n";
        T[x].build(1, 1, Len);
        for (register int i=1; i<=Len; ++i) pid[i] = tid[i];
//        for (int i=1; i<=len[x]; ++i) cerr << id[x][i] << ‘ ‘; cout << "  id end\n";
    }
    inline void deal(int x, int c) {
        ll p = c - add[x];
        if(T[x].w[1].a >= p) return ;
        else {
            int tp = T[x].find(1, 1, len[x], p);
            T[x].cover(1, 1, len[x], 1, tp, p);
        }
    }
    inline void main(int l, int r, int c) {
        register int L = bl[l], R = bl[r];
        if(L == R) deal(L, l, r, c);
        else {
            deal(L, l, end[L], c);
            deal(R, beg[R], r, c);
            for (register int i=L+1; i<R; ++i) deal(i, c);
        }
    }
}

namespace option3 {
    inline pa main(int x) {
        register int X = bl[x], *pid = id[X]; pa ret = pa(-inf, 0);
        for (register int i=1; i<=len[X]; ++i)
            if(pid[i] == x) {
                ret = T[X].gs(1, 1, len[X], i);
                break;
            }
        if(ret.a != -inf) ret.a += add[X];
        ret.t += addt[X];
        return ret;
    }
}

int main() {
    freopen("seq4.in", "r", stdin);
    freopen("seq.out", "w", stdout);
    const int BB = 32;
    n = getint();
    for (register int i=1; i<=n; ++i) p[i] = pa(getint(), 0);
    for (register int i=1; i<=n; ++i) bl[i] = (i-1)/BB + 1;
    m = bl[n];
    for (register int i=1; i<=m; ++i) beg[i] = (i-1)*BB+1, end[i] = i*BB; end[m] = n;
    for (register int i=1; i<=m; ++i) prepare :: deal(i);
    int Q = getint();
    static int l, r, c;
    static char ch;
    pa t;
    while(Q--) {
        ch = getchar();
        while(!isupper(ch)) ch = getchar();
//        T[1].debug(1, 1, len[1]);
//        for (int i=1; i<=len[1]; ++i) cout << id[1][i] << ‘ ‘; cout << endl;
        if(ch == ‘A‘) {
            l = getint(), r = getint(), c = getint();
            if(!c) continue;
            option1 :: main(l, r, c);
        } else if(ch == ‘M‘) {
            l = getint(), r = getint(), c = getint();
            option2 :: main(l, r, c);
        } else {
            l = getint();
            t = option3 :: main(l);
            printf(LLFORMAT " %d\n", t.a, t.t);
        }
    }
    return 0;
}

时间: 2024-10-12 22:53:34

省队集训 Day6 序列的相关文章

省队集训day6 C

Description 给定平面上的 N 个点, 其中有一些是红的, 其他是蓝的.现在让你找两条平行的直线, 使得在保证    不存在一个蓝色的点 被夹在两条平行线之间,不经过任何一个点, 不管是蓝色点还是红色点的前提下, 被夹在平行线之间的红色点个数最多 Input 第1行: 一个整数 N (1 <= N <= 1000)    第2..N+1行: 每行是一个点的坐标以及它的颜色.                坐标用2个 绝对值<10^9 的整数表示                颜

省队集训day6 A

code: 1 #include<cstdio> 2 #include<iostream> 3 #include<cmath> 4 #include<cstring> 5 #include<algorithm> 6 #define maxn 262146 7 #define mod 950009857 8 #define g 7 9 using namespace std; 10 typedef long long int64; 11 char

2015湖南省队集训DAY6——B题(BZOJ4179)

题面挺扯的,我就直接说人话算了. 题目大意:给你若干个病毒串,问你能不能构造出长度大于n的字符串使其中不出现任何一个字符串. 多组数据,总文件大小小于1M 题解: 联动:BZOJ2938 基本是原题,稍作了改动. 考虑ac自动机. 所求即为ac自动机中是否存在长度大于等于l的路径 先将所有的串插进去,然后构造失配指针. 显然的,插入后的末端节点肯定是不能经过的. 但仅这样显然是不可以的,我们考虑在匹配时,如果失配指针指向的节点是danger节点,那么这个节点也是不能经过的(显然). 所以考虑ac

省队集训day6 B

一道AC自动机题···· 一定要把一个节点没有的儿子接到它fai的儿子,否则会卡到n^2的······· 1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<algorithm> 5 #include<ctime> 6 #define maxn 1048580 7 #define maxl 10005 8 using namespace std; 9 typ

JS省队集训记

不知不觉省队集训已经结束,离noi也越来越近了呢 论考前实战训练的重要性,让我随便总结一下这几天的考试 Day 1 T1 唉,感觉跟xj测试很像啊?meet in middle,不过这种题不多测是什么心态? T2 唉,感觉好像做过类似的? T3 唉,怎么是提交答案题…… 感觉前两题都会,信心大增,于是决定先码T2 码了一会,过了第二个样列,还有一个样例?咦怎么过不去? 纠结了一会发现——读错题了,啪啪啪,全写错了……立马就凌乱了 赶快做T1,结果发现meet in middle的空间复杂度好像炸

关于举办第22届全国青少年信息学奥林匹克联赛浙江赛区颁奖大会暨省队集训、选拔的通知

各市科协.教育局,各有关学校: 第22届全国青少年信息学奥林匹克联赛(NOIP2016)成绩已公布,浙江赛区颁奖大会暨集训队首轮培训.选拔将由温州中学和省青少年科技教育协会承办. 我省将根据中国计算机学会<CCF关于2017NOI省内选拔的若干规定>和<浙江省青少年信息学奥林匹克竞赛实施办法>相关规定选拔.组建浙江省队参加于今年暑假期间举行的第34届全国青少年信息学奥林匹克竞赛(NOI2017),参赛名额由全国主办单位规定.现将集训.选拔.颁奖会有关事宜通知如下: 一.集训.选拔对

省队集训Day1 总统选举

[题目大意] 一个$n$个数的序列,$m$次操作,每次选择一段区间$[l, r]$,求出$[l, r]$中出现超过一半的数. 如果没有超过一半的数,那么就把答案钦定为$s$,每次会有$k$个数进行改变,给出下标,改变成当前的答案$s$. $n, m \leq 5*10^5, \sum k\leq 10^6$ By FJSDFZ ditoly [题解] 用这题的方法进行线段树操作即可:http://www.cnblogs.com/galaxies/p/20170602_c.html 但是这样需要验

FJOI省队集训 florida

省队成员(大部分)都没来...像我这种沙茶天天写写玄学算法都能排在榜上面...果然正解写挂的人远比暴力拍对的人少啊...陆陆续续会补一些题解.(不过有些题太神了可能补不上题解 有n个物品,两个袋子A和B.若物品i与j放在同一个袋子里,那么代价为T[i][j],保证T[i][i]=0,T[i][j]=T[j][i]. 一个袋子的代价D=袋子中两两物品代价的最大值.你需要将物品分配到两个袋子中,最小化D(A)+D(B). 2<=n<=250,0<=T[i][j]<=10^9. 陈旭大爷

HNOI 2016 省队集训日记

第一天 DeepDarkFantasy 从东京出发,不久便到一处驿站,写道:日暮里.  ——鲁迅<藤野先生> 定义一个置换的平方为对1~n的序列做两次该置换得到的序列.已知一个置换的平方,并且这个结果是一个排列,求该置换. 输入第一行一个数n表示排列长度,接下来一行n个数描述排列. 有解则输出一行n个数表示原排列.否则输出一行一个-1. 测试点编号 特征 0~1 n<=10 2~9 n<=1000000 此题有spj. 考试的时候懵逼了,根本没想清就开始乱打. 题解:由题易得每一个