• BZOJ 3211 花神游历各国


    题意:

    给出N(<=1e5)个数,每个数字在[1, 1e9]这个范围,有m(<=2e5)次操作,分为两种,①将区间[L, R]所有数开平方,②询问区间[L, R]数字之和。

    题解:

    1.因为每个数字在1e9以内那么开平方到1,次数小于10的,所以想要每次开方跳过为1的数,现在就将操作改为单点修改,复杂度也满足。

    2.现在的问题是单点修改,询问区间和了,树状数组就可以解决~(≧▽≦)/~

    3.但是怎么才能每次开方跳过1呢?并查集可以维护,如果一个数开方以后等于1了,就将它连向它后面那个不为1的数,实现删除操作,具体见代码~

    代码:

    /**************************************************************
        Problem: 3211
        User: Xgtao
        Language: C++
        Result: Accepted
        Time:1140 ms
        Memory:5908 kb
    ****************************************************************/
     
    #include <cstdio>
    #include <cmath>
    #include <iostream>
    using namespace std;
     
    #define lowbit(i) i&-i
    #define ll long long
    const int N = 1e5 + 7;
    int pa[N], n, m, o, L, R, x[N];
    ll S[N];
     
    int readint () {
        int K = 0;
        char c = getchar ();
        while (c < '0' || c > '9') c = getchar ();
        while (c >= '0' && c <= '9') K = K * 10 + c - '0', c = getchar ();
        return K;
    }
     
    int find (int x) {
        return pa[x] == x ? x : pa[x] = find (pa[x]);
    }
     
    void update (int x, int w) {
        for (int i = x; i < N; i += lowbit (i)) S[i] += w;
    }
     
    ll sum (int x) {
        ll ret = 0;
        for (int i = x; i >= 1; i -= lowbit (i)) ret += S[i];
        return ret;
    }
     
    int main () {
        n = readint();
        for (int i = 1; i <= n + 1; ++i) pa[i] = i;
        for (int i = 1; i <= n; ++i) {
            x[i] = readint();
            if (x[i] == 1 || x[i] == 0) pa[i] = find (i + 1);
            update (i, x[i]);
        }
        m = readint();
        while (m--) {
            o = readint(), L = readint(), R = readint();
            if (o == 1) printf ("%lld
    ", sum (R) - sum (L - 1));
            else if (o == 2) {
                for (int i = find (L); i <= R; i = find (i + 1)) {
                    update (i, (int)sqrt (x[i]) - x[i]);
                    x[i] = sqrt (x[i]);
                    if (x[i] == 1) pa[i] = find (i + 1);
                }
            }
        }
        return 0;
    }
    

      

    总结:

    并查集的姿势很重要,链表式的套路要好好掌握啊~

  • 相关阅读:
    可视化工具D3.js教程 入门 (第十三章)—— 树状图
    可视化工具D3.js教程 入门 (第十二章)—— 力导向图
    可视化工具D3.js教程 入门 (第十一章)—— 饼图
    可视化工具D3.js教程 入门 (第十章)—— 交互式操作
    vue滑动页面选中标题,选中标题滚动到指定区域
    Vue样式穿透
    操作系统:进程和线程+进程的通讯方式
    客户端与服务端长连接的几种方式
    前端性能优化的 24 条建议(2020)-收藏
    idea中修改git提交代码的用户名
  • 原文地址:https://www.cnblogs.com/xgtao/p/5968549.html
Copyright © 2020-2023  润新知