势能线段树专题

P4145 上帝造题的七分钟 2 / 花神游历各国

代码

每个数字最多进行6次操作会变成1
假如区间内的数字都是1,即可停止操作

const int N = 100010;
int a[N];
struct T {
    int l, r, val, tag;
} tr[N << 2];
void pushup(int p) {
    tr[p].val = tr[p << 1].val + tr[p << 1 | 1].val;
    tr[p].tag = tr[p << 1].tag + tr[p << 1 | 1].tag;
}
void build(int p, int l, int r) {
    if (l == r) {
        tr[p] = {l, r, a[l], 0};
        return;
    }
    tr[p] = {l, r, 0, 0};
    int mid = l + r >> 1;
    build(p << 1, l, mid);
    build(p << 1 | 1, mid + 1, r);
    pushup(p);
}
int query(int p, int l, int r) {
    if (tr[p].l >= l and tr[p].r <= r) return tr[p].val;
    int mid = tr[p].l + tr[p].r >> 1;
    if (l > mid) return query(p << 1 | 1, l, r);
    else if (r <= mid) return query(p << 1, l, r);
    return query(p << 1, l, r) + query(p << 1 | 1, l, r);
}
void modify(int p, int l, int r) {
    if (tr[p].tag == tr[p].r - tr[p].l + 1) {
        return;
    }
    else {
        if (tr[p].l == tr[p].r) {
            if (tr[p].val <= 1) {
                tr[p].tag = 1;
            } else {
                tr[p].tag = 0;
            }
            tr[p].val = sqrt(tr[p].val);
            if (tr[p].val <= 1) tr[p].tag = 1;
            else tr[p].tag = 0;
            return;
        } else {
            int mid = tr[p].l + tr[p].r >> 1;
            if (l <= mid) modify(p<<1, l, r);
            if (r > mid) modify(p<<1|1, l, r);
            pushup(p);
        }
    }
}
void solve(int Case) {
    int n, m;
    cin >> n ;
    for (int i = 1; i <= n; i++) cin >> a[i];
    build(1, 1, n);
    cin >> m;
    for (; m--;) {
        int k, l, r;
        cin >> k >> l >> r;
        if (!k) modify(1, min(l, r), max(l, r));
        else cout << query(1, min(l, r), max(l, r)) << nline;

    }
} 

势能线段树二

代码

任然是每个数字最多开6次,但是区间加和之后会影响到原来的数字,假如区间的数字都相同,只需要把和变成sqrt(sun/len),这样就可以使用懒标记

const int N = 500010;
#define ls(x) x<<1
#define rs(x) x<<1|1
struct tree {
    int l, r;
    int add, sum, mmax, mmin;
};
int a[N];
struct Segment_Tree {
    tree tr[N << 2];

    void pushup(tree &p, tree &l, tree &r) {
        p.sum = l.sum + r.sum;
        p.mmax = max(l.mmax, r.mmax);
        p.mmin = min(l.mmin, r.mmin);
    }
    void cal_tag(int p, int add) {
        tr[p].sum += (tr[p].r - tr[p].l + 1) * add;
        tr[p].mmin += add;
        tr[p].mmax += add;
        tr[p].add += add;
    }
    void pushdown(int u) {
        if (tr[u].add) {
            cal_tag(u << 1, tr[u].add);
            cal_tag(u << 1|1, tr[u].add);
            tr[u].add = 0;
        }
    }
    void pushup(int p) {
        pushup(tr[p], tr[ls(p)], tr[rs(p)]);
    }
    void build(int p, int l, int r) {
        if (l == r) tr[p] = {l, r, 0, a[l], a[l], a[l]};
        else {
            tr[p] = {l, r, 0, 0, 0, 0};
            int mid = l + r >> 1;
            build(ls(p), l, mid), build(rs(p), mid + 1, r);
            pushup(p);
        }
    }
    void modify(int p, int l, int r, int d) {
        if (tr[p].l >= l and tr[p].r <= r) {
            cal_tag(p, d);
        }
        else {//分裂
            pushdown(p);
            int mid = tr[p].l + tr[p].r >> 1;
            if (l <= mid) modify(ls(p), l, r, d);
            if (r > mid) modify(rs(p), l, r, d);
            pushup(p);
        }

    }
    tree query(int p, int l, int r) {
        if (tr[p].l >= l and tr[p].r <= r) return tr[p];
        else {
            pushdown(p);//分裂
            int mid = tr[p].l + tr[p].r >> 1;
            if (r <= mid) return query(ls(p), l, r);
            if (l > mid) return query(rs(p), l, r);
            else {
                auto left = query(ls(p), l, r);
                auto right = query(rs(p), l, r);
                tree ret;
                pushup(ret, left, right);
                return ret;

            }
        }
    }
    void change(int p, int l, int r) {
        if (tr[p].l >= l and tr[p].r <= r) {
            if (tr[p].mmax == tr[p].mmin) {
                int val = tr[p].mmax;
                val = sqrt(val);
                tr[p].sum = val * (tr[p].r - tr[p].l + 1);
                tr[p].add -= (tr[p].mmax - val);
                tr[p].mmax = tr[p].mmin = val;
                return ;
            }
        }
        pushdown(p);
        int mid = tr[p].l + tr[p].r >> 1;
        if (l <= mid) change(p << 1, l, r);
        if (r > mid) change(p << 1 | 1, l, r);
        pushup(p);
    }
};
Segment_Tree ST;

void solve(int Case) {
    int n, m;
    scanf("%lld%lld", &n, &m );
    for (int i = 1; i <= n; i++) scanf("%lld", &a[i]);
    ST.build(1, 1, n);
    for (int i = 1; i <= m; i++) {
        int opt, l, r, x;
        scanf("%lld%lld%lld", &opt, &l, &r);
        if (opt == 1) {
            ST.change(1, l, r);
        } else if (opt == 2) {
            scanf("%lld", &x);
            ST.modify(1, l, r, x);
        } else {
            printf("%lld\n", ST.query(1, l, r).sum);
        }
    }

}

D. The Child and Sequence

区间取模,区间最大值小于mod不需要操作

代码

#define ls(x) x<<1
#define rs(x) x<<1 |1
const int N = 500010;
int a[N];
struct tree {
    int l, r;
    int sum, mmax;
};
struct Segment_Tree {
    tree tr[N << 2];
    int pos[N];
    void pushup(tree &p, tree &l, tree &r) {
        p.sum = l.sum + r.sum;
        p.mmax = max(l.mmax, r.mmax);
    }
    void pushup(int p) {
        pushup(tr[p], tr[ls(p)], tr[rs(p)]);
    }
    void build(int p, int l, int r) {
        if (l == r) {
            tr[p] = {l, r, a[l], a[l]};
            pos[l] = p;
        }
        else {
            tr[p] = {l, r, 0, 0};
            int mid = l + r >> 1;
            build(ls(p), l, mid);
            build(rs(p), mid + 1, r);
            pushup(p);
        }
    }
    void modify1(int p, int x, int y) {
        p = pos[x];
        tr[p] = {x, x, y, y};
        for (; p >>= 1;) pushup(p);
    }
    tree query(int p, int l, int r) {
        if (tr[p].l >= l and tr[p].r <= r) return tr[p];
        int mid = tr[p].l + tr[p].r >> 1;
        if (r <= mid) return query(ls(p), l, r);
        else if (l > mid) return query(rs(p), l, r);
        else {
            tree ret;
            auto left = query(ls(p), l, r);
            auto right = query(rs(p), l, r);
            pushup(ret, left, right);
            return ret;
        }
    }
    void change(int p, int l, int r, int mod) {
        if (tr[p].mmax < mod) return;
        if (tr[p].l >= l and tr[p].r <= r) {
            if (tr[p].l == tr[p].r and tr[p].mmax >= mod) {
                tr[p].sum %= mod;
                tr[p].mmax %= mod;
                return;
            }
        }
        int mid = tr[p].l + tr[p].r >> 1;
        if (l <= mid) change(p << 1, l, r, mod);
        if (r > mid) change(p << 1 | 1, l, r, mod);
        pushup(p);
    }
};
Segment_Tree ST;
void solve(int Case) {
    int n, m;
    scanf("%lld%lld", &n, &m );
    for (int i = 1; i <= n; i++) scanf("%lld", &a[i]);
    ST.build(1, 1, n);
    //printf("%lld\n", ST.query(1, 1, n).sum);
    for (int i = 1; i <= m; i++) {
        int opt, l, r, x;
        scanf("%lld%lld%lld", &opt, &l, &r);
        if (opt == 1) {
            printf("%lld\n", ST.query(1, l, r).sum);
        } else if (opt == 2) {
            scanf("%lld", &x);
            ST.change(1, l, r, x);
        } else {
            ST.modify1(1, l, r);
        }
    }
 
 
}

F. SUM and REPLACE

代码

当区间中的最大值小于等于2时就不需要操作

#define ls(x) x<<1
#define rs(x) x<<1 |1
const int N = 500010, M = N * 2;
int f[M];
void init() {
    for (int i = 1; i < M; i++) {
        for (int j = i; j < M; j += i) {
            f[j]++;
        }
    }
}
int a[N];
struct tree {
    int l, r;
    int sum, mmax;
};
struct Segment_Tree {
    tree tr[N << 2];
    int pos[N];
    void pushup(tree &p, tree &l, tree &r) {
        p.sum = l.sum + r.sum;
        p.mmax = max(l.mmax, r.mmax);
    }
    void pushup(int p) {
        pushup(tr[p], tr[ls(p)], tr[rs(p)]);
    }
    void build(int p, int l, int r) {
        if (l == r) {
            tr[p] = {l, r, a[l], a[l]};
            pos[l] = p;
        }
        else {
            tr[p] = {l, r, 0, 0};
            int mid = l + r >> 1;
            build(ls(p), l, mid);
            build(rs(p), mid + 1, r);
            pushup(p);
        }
    }
    void modify1(int p, int x, int y) {
        p = pos[x];
        tr[p] = {x, x, y, y};
        for (; p >>= 1;) pushup(p);
    }
    tree query(int p, int l, int r) {
        if (tr[p].l >= l and tr[p].r <= r) return tr[p];
        int mid = tr[p].l + tr[p].r >> 1;
        if (r <= mid) return query(ls(p), l, r);
        else if (l > mid) return query(rs(p), l, r);
        else {
            tree ret;
            auto left = query(ls(p), l, r);
            auto right = query(rs(p), l, r);
            pushup(ret, left, right);
            return ret;
        }
    }
    void change(int p, int l, int r) {
        if (tr[p].mmax <= 2) return;
        if (tr[p].l >= l and tr[p].r <= r) {
            if (tr[p].mmax < 2) return;
            if (tr[p].l == tr[p].r and tr[p].mmax > 2) {
                tr[p].sum = f[tr[p].sum];
                tr[p].mmax = f[tr[p].mmax];
                return;
            }
        }
        int mid = tr[p].l + tr[p].r >> 1;
        if (l <= mid) change(p << 1, l, r);
        if (r > mid) change(p << 1 | 1, l, r);
        pushup(p);
    }
};
Segment_Tree ST;
void solve(int Case) {
    int n, m;
    scanf("%lld%lld", &n, &m);
    for (int i = 1; i <= n; i++) scanf("%lld", &a[i]);
    ST.build(1, 1, n);
    for (int i = 1; i <= m; i++) {
        int opt, a, b;
        scanf("%lld%lld%lld", &opt, &a, &b);
        if (opt == 1) {
            ST.change(1, a, b);
        } else {
            printf("%lld\n", ST.query(1, a, b).sum);
        }
    }
}

D. Lowbit

代码:

每个数字加上自己的lowbit,当区间中每个数字都是2的整数次幂,就是区间乘2,可以使用懒标记

#define ls(x) x<<1
#define rs(x) x<<1|1
struct tree {
    int l, r;
    int sum, tag, mul;
};
int a[N];
#define lowbit(x) x&(-x)
bool check(int x) {
    return (x > 0 and (x & (x - 1)) == 0);
}
struct Segment_Tree {
    tree tr[N << 2];
    void pushup(tree &p, tree &l, tree &r) {
        p.sum = (l.sum + r.sum) % mod;
        p.tag = l.tag & r.tag;
    }
    void cal_tag(int p, int mul) {
        tr[p].sum = tr[p].sum % mod * mul % mod;
        tr[p].mul = tr[p].mul % mod * mul % mod;
    }
    void pushdown(int p) {
        if (tr[p].mul != 1) {
            cal_tag(p << 1, tr[p].mul);
            cal_tag(p << 1 | 1, tr[p].mul);
            tr[p].mul = 1;
        }
    }
    void pushup(int p) {
        pushup(tr[p], tr[ls(p)], tr[rs(p)]);
    }
    void build(int p, int l, int r) {
        if (l == r) tr[p] = {l, r, a[l], 0, check(a[l])};
        else {
            tr[p] = {l, r, 0, 0, 1};
            int mid = l + r >> 1;
            build(ls(p), l, mid), build(rs(p), mid + 1, r);
            pushup(p);
        }
    }
    void modify(int p, int l, int r, int d) {
        if (tr[p].l >= l and tr[p].r <= r) {
            cal_tag(p, d);
        }
        else {//分裂
            pushdown(p);
            int mid = tr[p].l + tr[p].r >> 1;
            if (l <= mid) modify(ls(p), l, r, d);
            if (r > mid) modify(rs(p), l, r, d);
            pushup(p);
        }
 
    }
    tree query(int p, int l, int r) {
        if (tr[p].l >= l and tr[p].r <= r) return tr[p];
        else {
            pushdown(p);//分裂
            int mid = tr[p].l + tr[p].r >> 1;
            if (r <= mid) return query(ls(p), l, r);
            if (l > mid) return query(rs(p), l, r);
            else {
                auto left = query(ls(p), l, r);
                auto right = query(rs(p), l, r);
                tree ret;
                pushup(ret, left, right);
                return ret;
 
            }
        }
    }
    void change(int p, int l, int r) {
        if (tr[p].l >= l and tr[p].r <= r) {
            if (tr[p].tag) {
                modify(p, tr[p].l, tr[p].r, 2);
                return;
            }
            if (tr[p].l == tr[p].r) {
                int val = tr[p].sum;
                val = val + (lowbit(val));
                tr[p].tag = check(val);
                tr[p].sum = val;
                return;
            }
        }
        pushdown(p);
        int mid = tr[p].l + tr[p].r >> 1;
        if (l <= mid) change(p << 1, l, r);
        if (r > mid) change(p << 1 | 1, l, r);
        pushup(p);
    }
};
Segment_Tree ST;
 
 
void solve(int Case) {
    int n, m;
    scanf("%lld", &n);
    for (int i = 1; i <= n; i++) {
        scanf("%lld", &a[i]);
    }
    ST.build(1, 1, n);
    scanf("%lld", &m);
    for (int i = 1; i <= m; i++) {
        int opt, l, r;
        scanf("%lld%lld%lld", &opt, &l, &r);
        if (opt == 1) {
            ST.change(1, l, r);
        } else {
            printf("%lld\n", ST.query(1, l, r).sum % mod);
        }
    }
 
}

Counting Stars

区间加自己的lowbit,或者自己的highbit

代码:

把一个数字的最高位和其他位分开讨论,每次加highbit相当于给最高位*2,每次减去lowbit,相当于减去一个1,
维护每个数字1的个数,当区间最大的1的个数为0时不需要操作,


const int N = 500010, mod = 998244353;

#define ls(x) x<<1
#define rs(x) x<<1|1
struct tree {
    int l, r;
    int sum, hb, lb;
    int mul;
};
int a[N];
#define lowbit(x) x&(-x)
bool check(int x) {
    return (x > 0 and (x & (x - 1)) == 0);
}
int highbit(int x) {
    int cnt = 0;
    while (x) cnt++, x >>= 1;
    return 1LL << (cnt - 1);
}

struct Segment_Tree {
    tree tr[N << 2];
    void pushup(tree &p, tree &l, tree &r) {
        p.sum = max(l.sum, r.sum);
        p.lb = (l.lb + r.lb) % mod;
        p.hb = (l.hb + r.hb) % mod;
    }
    void cal_tag(int p, int mul) {
        tr[p].hb = tr[p].hb % mod * mul % mod;
        tr[p].mul = tr[p].mul % mod * mul % mod;
    }
    void pushdown(int p) {
        if (tr[p].mul != 1) {
            cal_tag(p << 1, tr[p].mul);
            cal_tag(p << 1 | 1, tr[p].mul);
            tr[p].mul = 1;
        }
    }
    void pushup(int p) {
        pushup(tr[p], tr[ls(p)], tr[rs(p)]);
    }
    void build(int p, int l, int r) {
        if (l == r) tr[p] = {l, r,  __builtin_popcount(a[l]), highbit(a[l]), a[l] - highbit(a[l]), 1};
        else {
            tr[p] = {l, r, 0, 0, 0, 1};
            int mid = l + r >> 1;
            build(ls(p), l, mid), build(rs(p), mid + 1, r);
            pushup(p);
        }
    }
    void modify(int p, int l, int r, int d) {
        if (tr[p].l >= l and tr[p].r <= r) {
            cal_tag(p, d);
        }
        else {//分裂
            pushdown(p);
            int mid = tr[p].l + tr[p].r >> 1;
            if (l <= mid) modify(ls(p), l, r, d);
            if (r > mid) modify(rs(p), l, r, d);
            pushup(p);
        }

    }
    tree query(int p, int l, int r) {
        if (tr[p].l >= l and tr[p].r <= r) return tr[p];
        else {
            pushdown(p);//分裂
            int mid = tr[p].l + tr[p].r >> 1;
            if (r <= mid) return query(ls(p), l, r);
            if (l > mid) return query(rs(p), l, r);
            else {
                auto left = query(ls(p), l, r);
                auto right = query(rs(p), l, r);
                tree ret;
                pushup(ret, left, right);
                return ret;

            }
        }
    }
    void change1(int p, int l, int r) {
        if (tr[p].l >= l and tr[p].r <= r) {
            if (!tr[p].sum) return;
            modify(p, tr[p].l, tr[p].r, 2);
            return;
        }
        pushdown(p);
        int mid = tr[p].l + tr[p].r >> 1;
        if (l <= mid) change1(p << 1, l, r);
        if (r > mid) change1(p << 1 | 1, l, r);
        pushup(p);
    }
    void change2(int p, int l, int r) {
        if (tr[p].l >= l and tr[p].r <= r) {
            if (!tr[p].sum) return;
            if (tr[p].l == tr[p].r) {
                int val = tr[p].lb;
                val -= lowbit(val);
                tr[p].sum--;
                tr[p].lb = val;
                if (!tr[p].sum) tr[p].hb = 0;
                return;
            }
        }
        pushdown(p);
        int mid = tr[p].l + tr[p].r >> 1;
        if (l <= mid) change2(p << 1, l, r);
        if (r > mid) change2(p << 1 | 1, l, r);
        pushup(p);
    }
};
Segment_Tree ST;


void solve(int Case) {
    int n, m;
    scanf("%lld", &n);
    for (int i = 1; i <= n; i++) {
        scanf("%lld", &a[i]);
    }
    ST.build(1, 1, n);
    scanf("%lld", &m);
    for (int i = 1; i <= m; i++) {
        int opt, l, r;
        scanf("%lld%lld%lld", &opt, &l, &r);
        if (opt == 2) {
            ST.change2(1, l, r);
        } else if (opt == 3) {
            ST.change1(1, l, r);
        } else {
            tree res = ST.query(1, l, r);
            printf("%lld\n", (res.hb % mod + res.lb % mod) % mod);
        }
    }
}
posted @ 2022-05-02 12:26  指引盗寇入太行  阅读(60)  评论(0编辑  收藏  举报