bzoj4540: [Hnoi2016]序列
来源:互联网 发布:deepin debian ubuntu 编辑:程序博客网 时间:2024/05/10 18:17
题目链接
bzoj4540
题目描述
Description
给定长度为n的序列:a1,a2,…,an,记为a[1:n]。类似地,a[l:r](1≤l≤r≤N)是指序列:al,al+1,…,ar-1,ar。若1≤l≤s≤t≤r≤n,则称a[s:t]是a[l:r]的子序列。现在有q个询问,每个询问给定两个数l和r,1≤l≤r≤n,求a[l:r]的不同子序列的最小值之和。例如,给定序列5,2,4,1,3,询问给定的两个数为1和3,那么a[1:3]有6个子序列a[1:1],a[2:2],a[3:3],a[1:2],a[2:3],a[1:3],这6个子序列的最小值之和为5+2+4+2+2+2=17。
Input
输入文件的第一行包含两个整数n和q,分别代表序列长度和询问数。接下来一行,包含n个整数,以空格隔开
,第i个整数为ai,即序列第i个元素的值。接下来q行,每行包含两个整数l和r,代表一次询问。
Output
对于每次询问,输出一行,代表询问的答案。
Sample Input
5 5
5 2 4 1 3
1 5
1 3
2 4
3 5
2 5
Sample Output
28
17
11
11
17
HINT
1 ≤N,Q ≤ 100000,|Ai| ≤ 10^9
题解
这里提供一种
我们考虑使用莫队算法,当左右端点移动时,只会增加或删除以某个元素开头或结尾的子串。这里我们考虑右端点右移至
#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>#include<cmath>#include<queue>#include<vector>using namespace std;const int N=100010;int stk[N],a[N],rmq[N][20],r[N],l[N],Log[N],top,S,n,m,x,y;long long ans[N],dl[N],dr[N],now;struct query{ int l,r,id; friend bool operator <(const query &a,const query &b){ if(a.l/S==b.l/S) return a.r<b.r; return a.l/S<b.l/S; }}q[N];inline void Read(int &x){ static char c; int f=1; for(c=getchar();c<'0'||c>'9';c=getchar()) if(c=='-') f=-1; for(x=0;c>='0'&&c<='9';c=getchar()) x=x*10+c-'0'; x=x*f;}int query(int l,int r){ int tmp=Log[r-l+1]; if(a[rmq[l][tmp]]<a[rmq[r-(1<<tmp)+1][tmp]]) return rmq[l][tmp]; else return rmq[r-(1<<tmp)+1][tmp];}void changel(int l,int r,long long k){ int tmp=query(l,r); now+=k*a[tmp]*(r-tmp+1); now+=k*(dr[l]-dr[tmp]);}void changer(int l,int r,long long k){ int tmp=query(l,r); now+=k*a[tmp]*(tmp-l+1); now+=k*(dl[r]-dl[tmp]);}void pretreat(){ for(int i=1;i<=n;i++) Log[i]=(int)log2(i); for(int i=1;i<=n;i++){ while(top&&a[stk[top]]>a[i]) r[stk[top--]]=i; l[i]=a[stk[top]]==a[i]?l[stk[top]]:stk[top]; stk[++top]=i; } while(top) r[stk[top--]]=n+1; for(int i=1;i<=n;i++) dl[i]=dl[l[i]]+1ll*(i-l[i])*a[i]; for(int i=n;i;i--) dr[i]=dr[r[i]]+1ll*(r[i]-i)*a[i]; for(int i=1;i<=n;i++) rmq[i][0]=i; for(int i=1;(1<<i)<=n;i++) for(int j=1;j<=n-(1<<i)+1;j++) if(a[rmq[j][i-1]]<a[rmq[j+(1<<(i-1))][i-1]]) rmq[j][i]=rmq[j][i-1]; else rmq[j][i]=rmq[j+(1<<(i-1))][i-1];}int main(){ Read(n); Read(m); S=(int)sqrt(n); for(int i=1;i<=n;i++) Read(a[i]); pretreat(); for(int i=1;i<=m;i++){ Read(q[i].l); Read(q[i].r); q[i].id=i; } sort(q+1,q+1+m); x=y=1; now=a[1]; for(int i=1;i<=m;i++){ if(q[i].r>y) while(y!=q[i].r) y++,changer(x,y,1); if(q[i].l>x) while(x!=q[i].l) changel(x,y,-1),x++; if(q[i].l<x) while(x!=q[i].l) x--,changel(x,y,1); if(q[i].r<y) while(y!=q[i].r) changer(x,y,-1),y--; ans[q[i].id]=now; } for(int i=1;i<=m;i++) printf("%lld\n",ans[i]); return 0;}
- bzoj4540: [Hnoi2016]序列
- bzoj4540: [Hnoi2016]序列
- BZOJ4540 HNOI2016 序列
- 【HNOI2016】【BZOJ4540】序列
- BZOJ4540 [Hnoi2016]序列
- bzoj4540【HNOI2016】序列
- [题解]bzoj4540 HNOI2016 序列
- bzoj4540: [Hnoi2016]序列
- 【BZOJ4540】【Hnoi2016】序列 线段树
- Bzoj4540:[Hnoi2016]序列:莫队+RMQ
- [bzoj4540][Hnoi2016]序列 莫队+RMQ
- 【bzoj4540】【HNOI2016】【序列】【莫队+st表】
- bzoj4540 [Hnoi2016]序列 (莫队+ST表+单调栈)
- [BZOJ4540]序列
- bzoj4540 序列
- 【HNOI2016】序列
- bzoj 4540: [Hnoi2016]序列
- [Hnoi2016]序列 解题报告
- HDU 1024 Max Sum Plus Plus求前n个数中的若干个数分为连续的m段的最大和值(解析)
- DP———1001
- Window和WindowManager
- 山东省第五届ACM大学生程序设计竞赛 Hearthstone II 组合数学 Stirling数
- uboot的源码目录分析1
- bzoj4540: [Hnoi2016]序列
- deep learning CNN 几个疑问
- oc 中的SEL
- HDU 1029 Ignatius and the Princess IV(动规水题,有个很精妙的快解法)
- LeetCode 307. Range Sum Query - Mutable(区间之和)
- metaspolit 安装后无法启动命令行msfcli的解决方法
- Android官方文档之Introduction
- bzoj4542: [Hnoi2016]大数
- 198. House Robber