zoukankan      html  css  js  c++  java
  • 「HNOI2016」序列

    [HNOI2016]序列 草稿纸

    P3246 [HNOI2016]序列
    给定一个长度为n的序列,q个询问,每次询问[l,r]的所有子段的最小值之和。

    设f[i]为以i为右端点的区间答案,pre[i]为i左边第一个比a[i]小的数的位置。 可以发现如果这个左端点<=pre[i],其实右端点放在pre[i]和放在i答案是一样的。
    所以有(f[i]=a[i]*(i-pre[i])+f[pre[i]])
    (=>f[i]-f[pre[i]]=a[i]*(i-pre[i]))(其实是左端点在pre[i]+1~i之间,右端点在i的答案)
    又或者(f[i]=a[i]*(i-pre[i])+a[pre[i]]*(pre[i]-pre[pre[i]])+f[pre[pre[i]]])
    (=>f[i]-f[pre[pre[i]]]=(f[i]-f[pre[i]])+(f[pre[i]]-f[pre[pre[i]]])=a[i]*(i-pre[i])+a[pre[i]]*(pre[i]-pre[pre[i]]))(其实是左端点在pre[pre[i]]+1~i之间,右端点在i的答案)(这样一定可以处理左端点为i左边一个比i小的数到i这个区间的答案)

    然后就考虑左端点在([l,r]),右端点在(r+1)的答案....
    那么其实可以p=r+1; while (pre[p]>=l) p=pre[p]; 其实发现这样最后得到的p就是[l,r+1]的最小值位置,用RMQ可以O1或Ologn求出
    r+1的时候答案的增量计算分为两部分
    对于左端点在([p+1,r+1]),右端点在(r+1)的部分,答案就为(f[r+1]-f[p])
    对于左端点在([l,p]),右端点在(r+1)的部分,答案就为(a[p]*(p-l+1))
    这样可以离线询问Onsqrtn莫队完成

    在线怎么写(
    直接考虑一个区间([l,r])的答案
    w...怎么搞呢
    考虑右端点在r的答案...同样找出一个最小值位置p。
    那么左端点在([p+1,r])的答案是(f[r]-f[p])

    右端点在(r-1),左端点在([p+1,r-1])的答案是(f[r-1]-f[p])
    那左端点在([p+1,右端点]),右端点在([p+1,r]),也即([p+1,r])区间内的答案为 (( Sigma_{i = p+1}^{r} f[i] ) - f[p]*(r-p))
    对f做个前缀和数组c 答案就是 (c[r]-c[p]-f[p]*(r-p))

    ([l,p-1])区间内的答案,可以倒过来求的样子(
    答案是 (c[p-1]-c[l-1]-f[p]*(p-l))

    覆盖p的区间答案,(a[p]*(p-l+1)*(r-p+1))

    QAQ 完结....居然写了这么久思路才理清楚

    code:
    一遍过样例,爆long long 喜提0pts,暴躁kkz在线#define int long long

    #include <algorithm>
    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <cmath>
    using namespace std;
    #define MAXN (int)(1e5+233)
    #define MAXA (int)(1e9+233)
    #include <stack>
    struct qwq
    {
    	long long a,id;
    };
    stack<qwq> st;
    #define int long long
    int a[MAXN];
    int n,q;
    
    int prer[MAXN],prel[MAXN];
    
    
    
    inline void mostack()
    {
    	for (int i=1;i<=n;i++)
    	{
    		while (!st.empty()&&st.top().a>a[i])
    		{
    			prer[st.top().id]=i;
    			st.pop();
    		}
    		st.push((qwq){a[i],i});
    	}
    	while (!st.empty()) st.pop();
    	for (int i=n;i;i--)
    	{
    		while (!st.empty()&&st.top().a>a[i])
    		{
    			prel[st.top().id]=i;
    			st.pop();
    		}
    		st.push((qwq){a[i],i});
    	}
    	return;
    }
    int ans[MAXN<<2];
    #define leftson cur<<1
    #define rightson cur<<1|1
    #define mid ((l+r)>>1)
    #define push_up if (a[ans[leftson]]<a[ans[rightson]]) ans[cur]=ans[leftson]; else ans[cur]=ans[rightson]
    void build(int cur,int l,int r)
    {
    	if (l==r)
    	{
    		ans[cur]=l;
    		return;
    	}
    	build(leftson,l,mid);
    	build(rightson,mid+1,r);
    	push_up;
    }
    int query(int ql,int qr,int cur,int l,int r)
    {
    	if (ql<=l&&r<=qr) return ans[cur];
    	int answer=0;
    	if (ql<=mid) answer=query(ql,qr,leftson,l,mid);
    	if (qr>mid) { int tt=query(ql,qr,rightson,mid+1,r); if (!answer) answer=tt; else answer=(a[tt]>a[answer]?answer:tt); }
    	return answer;
    }
    
    inline void RMQINIT() { build(1,1,n); return; }
    long long fl[MAXN],cl[MAXN],fr[MAXN],cr[MAXN];
    inline void FINIT()
    {
    	for (int i=1;i<=n;i++)
    		fl[i]=a[i]*(i-prel[i])+fl[prel[i]];
    	for (int i=n;i;i--)
    		fr[i]=a[i]*(prer[i]-i)+fr[prer[i]];
    	for (int i=1;i<=n;i++)
    		cl[i]=cl[i-1]+fl[i];
    	for (int i=n;i;i--)
    		cr[i]=cr[i+1]+fr[i];
    	return;
    }
    
    signed main()
    {
    	scanf("%lld%lld",&n,&q);
    	for (int i=1;i<=n;i++) scanf("%lld",&a[i]);
    	mostack();
    	RMQINIT();
    	FINIT();
    	int l,r,p;
    	long long ans=0;
    	while (q--)
    	{
    		scanf("%lld%lld",&l,&r);
    		p=query(l,r,1,1,n);
    		ans=0;
    		if (p+1<=r) ans=cl[r]-cl[p]-fl[p]*(r-p);
    		if (p-1>=l) ans+=cr[l]-cr[p]-fr[p]*(p-l);
    		ans+=a[p]*(p-l+1)*(r-p+1);
    		printf("%lld
    ",ans);
    	}
    	return 0;
    }
    
    By ❤千柒/Kan_kiz
  • 相关阅读:
    mysql查看每张表的空间使用情况
    下一步开发的技术点
    技术体系需要继续探索的东西
    架构体系需要进一步研究探索的V2路线图
    串行写队列的MYSQL大文本参数
    Node.js 数据存储方式的选择
    Node.js npm 详解
    Node入门
    Node.js知识点学习
    为什么应使用 Node.js
  • 原文地址:https://www.cnblogs.com/Kan-kiz/p/15509916.html
Copyright © 2011-2022 走看看