• 【题解】HNOI2016序列


      也想了有半天,没有做出来……实际上做法确实也是十分精妙的。这里推荐一个blog,个人认为这位博主讲得挺好了:Sengxian's Blog;

      感觉启示是:首先要加强对莫队算法 & ST表的熟练程度。 在想与数列有关的问题的时候,要尽量多在草稿纸上手玩几组数据,观察其中的联系,应该可以观察到许多有用的性质。

      不过这题还有一个地方:网上的题解基本上都是先移动了右指针,后移动左指针;如果反过来,竟然被卡到只有10分。具体的原因我也不知道,但我猜想是不是由于r 和 l 的左右颠倒导致程序出现了一些问题,所以特判了一下,保证左指针永远在右指针的左侧。

    #include <bits/stdc++.h>
    using namespace std;
    #define maxn 200000
    #define int long long
    int n, q, B = 316, a[maxn];
    int ans, Ans[maxn];
    int top, S[maxn], Log[maxn];
    int LS[maxn], RS[maxn];

    struct ques
    {
        int l, r, id, bel;
        ques(int L = 0, int R = 0, int idx = 0)
        { l = L, r = R, id = idx, bel = (l / B) + 1; }
        bool operator < (const ques &q)
        const{
            return (bel < q.bel || (bel == q.bel && r < q.r));
        }
    }Q[maxn];

    int read()
    {
        int x = 0, k = 1;
        char c;
        c = getchar();
        while(c < '0' || c > '9') { if(c == '-') k = -1; c = getchar(); }
        while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
        return x * k;
    }

    namespace RMQ
    {
        int ST[maxn][20];
        int cmp(const int &i, const int &j) { return a[i] < a[j] ? i : j; }
        void Work()
        {
            for(int i = 2; i <= n; i ++) Log[i] = Log[i >> 1] + 1;
            for(int i = 1; i <= n; i ++) ST[i][0] = i;
            for(int j = 1, k = 1 << j; k <= n; j ++, k = 1 << j)
                for(int i = 1; k + i - 1 <= n; i ++)
                    ST[i][j] = cmp(ST[i][j - 1], ST[i + (k >> 1)][j - 1]);
        }
        
        int Get_min(int l, int r)
        {
            int k = Log[r - l + 1];
            return cmp(ST[l][k], ST[r - (1 << k) + 1][k]);
        }
    }

    void Get_Sum(int *LS)
    {
        S[top = 0] = 0;
        for(int i = 1; i <= n; i ++)
        {
            while(top && a[S[top]] >= a[i]) top --;
            LS[i] = LS[S[top]] + (i - S[top]) * a[i];
            S[++ top] = i;
        }
    }

    int Go_Right(int l, int r)
    {
        int pos = RMQ :: Get_min(l, r);
        return (pos - l + 1) * a[pos] + LS[r] - LS[pos];
    }

    int Go_Left(int l, int r)
    {
        int pos = RMQ :: Get_min(l, r);
        return (r - pos + 1) * a[pos] + RS[l] - RS[pos];
    }

    signed main()
    {
        n = read(), q = read(), B = sqrt(n) + 1;
        for(int i = 1; i <= n; i ++) a[i] = read();
        RMQ :: Work();
        for(int i = 1; i <= q; i ++)
        {
            int x = read(), y = read();
            Q[i] = ques(x, y, i);
        }
        sort(Q + 1, Q + 1 + q);
        a[0] = -2e9; Get_Sum(LS); reverse(a + 1, a + 1 + n);
        Get_Sum(RS); reverse(a + 1, a + 1 + n);
        reverse(RS + 1, RS + 1 + n);
        int l = 1, r = 1; ans = a[1];
        for(int i = 1; i <= q; i ++)
        {
            if(Q[i].l > r)
            {
                while(r < Q[i].r) ans += Go_Right(l, r + 1), r ++;
                while(r > Q[i].r) ans -= Go_Right(l, r), r --;    
                while(l < Q[i].l) ans -= Go_Left(l, r), l ++;
                while(l > Q[i].l) ans += Go_Left(l - 1, r), l --;
            }
            else
            {
                while(l < Q[i].l) ans -= Go_Left(l, r), l ++;
                while(l > Q[i].l) ans += Go_Left(l - 1, r), l --;
                while(r < Q[i].r) ans += Go_Right(l, r + 1), r ++;
                while(r > Q[i].r) ans -= Go_Right(l, r), r --;    
            }
            Ans[Q[i].id] = ans;
        }
        for(int i = 1; i <= q; i ++) printf("%lld ", Ans[i]);
        return 0;
    }
  • 相关阅读:
    找一个数组的最大和的连续子数组(时间复杂度 O(n))
    Web版需求征集系统所得2,servlet中request.getParameter获值乱码问题解决
    Web版需求征集系统所得1,servlet中获取checkbox复选框的值
    人月神话读后感(三)
    Web版记账本开发记录(三)开发过程遇到的问题小结2
    人月神话读后感(二)
    团队开发项目--校园知网 nabcd 需求分析
    软件工程--第六周学习进度
    软件工程--第五周学习进度
    人月神话阅读笔记03
  • 原文地址:https://www.cnblogs.com/twilight-sx/p/9256526.html
Copyright © 2020-2023  润新知