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
  • 相关阅读:
    (二分查找 拓展) leetcode 69. Sqrt(x)
    (二分查找 拓展) leetcode 162. Find Peak Element && lintcode 75. Find Peak Element
    (链表) lintcode 219. Insert Node in Sorted Linked List
    (二分查找 拓展) leetcode 34. Find First and Last Position of Element in Sorted Array && lintcode 61. Search for a Range
    (最短路 Floyd) P2910 [USACO08OPEN]寻宝之路Clear And Present Danger 洛谷
    (字符串 数组 递归 双指针) leetcode 344. Reverse String
    (二叉树 DFS 递归) leetcode 112. Path Sum
    (二叉树 DFS 递归) leetcode 101. Symmetric Tree
    (二叉树 递归) leetcode 144. Binary Tree Preorder Traversal
    (二叉树 递归 DFS) leetcode 100. Same Tree
  • 原文地址:https://www.cnblogs.com/Kan-kiz/p/15509916.html
Copyright © 2011-2022 走看看