bzoj4540: [Hnoi2016]序列
来源:互联网 发布:数据库查询怎么保存 编辑:程序博客网 时间:2024/05/21 05:21
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
题解
一开始还看错题了。。
弄了一上午QAQ
然后去看了下题解,才发现理解错了。。
于是趁没看懂赶紧溜了回来。。
于是我们考虑莫队吧。。(唯一看懂的东西就是莫队
然后我们处理两个东西,L和R,表示这个点能影响的范围,也就是比他小的范围
然后对于新增加的一个点,我们可以跳他的L,R来找答案,直到找出范围为止
大概的处理过程是这样的:
LL Ri (LL l,LL r){ LL x=r,re=0; while (x>=l) { LL t=L[x]; if (t<l) t=l; re=re+a[x]*(x-t+1); x=t-1; } return re;}LL Li (LL l,LL r){ LL x=l,re=0; while (x<=r) { LL t=R[x]; if (t>r) t=r; re=re+a[x]*(t-x+1); x=t+1; } return re;}void solve (){ LL l=1,r=1;LL ans=a[1]; for (LL u=1;u<=q;u++) { while (r<s[u].r) ans=ans+Ri(l,++r); while (l<s[u].l) ans=ans-Li(l++,r); while (l>s[u].l) ans=ans+Li(--l,r); while (r>s[u].r) ans=ans-Ri(l,r--); Ans[s[u].id]=ans; } for (LL u=1;u<=q;u++) printf("%lld\n",Ans[u]);}
然而数据很水,居然20S刚好跑过去了
但是这个做法,即使是随机数据,也是O
所以这个肯定是不行的
于是去认真地膜了一下题解。。
学会了st表的正确姿势
预处理出两个类似前缀和的数组sl[i]和sr[i]
其中sl[i]=sl[l[i]]+(i-l[i])*a[i],sr同理
表示以这个为结束的答案的前缀和
左端点在l[i]及以前的答案就是sl[l[i]],左端点在[l[i],i]之间的最小值肯定是a[i],所以答案加上(i-l[i])*a[i]
嗯,挺好的。。
就这样吧。。
CODE:
#include<cstdio>#include<cmath>#include<iostream>#include<algorithm>#include<cstring>#include<stack>using namespace std;typedef long long LL;const LL N=100005;LL n,q,nn;LL a[N];struct qq{LL l,r,id;}s[N];LL ans[N];LL belong[N];bool cmp (qq a,qq b){return belong[a.l]==belong[b.l]?a.r<b.r:belong[a.l]<belong[b.l];}LL L[N],R[N];//左边第一个比他小的数 右边第一个比他小的数 stack<LL> sta;LL sl[N],sr[N];LL lg[N];LL st[N][20];LL pw[20];LL getmin (LL x,LL y){return a[x]<a[y]?x:y;}void prepare (){ sta.push(1);L[1]=0; for (LL u=2;u<=n;u++) { while (!sta.empty()) { LL x=sta.top(); if (a[x]>=a[u]) sta.pop(); else break; } if (sta.empty()) L[u]=0; else L[u]=sta.top()+1; sta.push(u); } while (!sta.empty())sta.pop(); sta.push(n);R[n]=n+1; for (LL u=n-1;u>=1;u--) { while (!sta.empty()) { LL x=sta.top(); if (a[x]>=a[u]) sta.pop(); else break; } if (sta.empty()) R[u]=n+1; else R[u]=sta.top()-1; sta.push(u); } for (LL u=n;u>=1;u--) sr[u]=sr[R[u]+1]+(R[u]-u+1)*a[u]; for (LL u=1;u<=n;u++) sl[u]=sl[L[u]-1]+(u-L[u]+1)*a[u]; /*for (LL u=1;u<=n;u++) printf("%lld ",sl[u]); printf("\n"); for (LL u=1;u<=n;u++) printf("%lld ",sr[u]); printf("\n");*/}void pre_st (){ lg[0]=-1;for (LL u=1;u<=n;u++) lg[u]=lg[u>>1]+1; pw[0]=1;for (LL u=1;u<=18;u++) pw[u]=pw[u-1]<<1; for (LL u=1;u<=n;u++) st[u][0]=u; for (LL u=1;u<=18;u++) { for (LL i=1;i<=n;i++) { st[i][u]=st[i][u-1]; if (i+pw[u-1]<=n) st[i][u]=getmin(st[i][u-1],st[i+pw[u-1]][u-1]); } }}LL Ans[N];LL calc (LL x,LL y){ if (x>y) swap(x,y); LL l=lg[y-x+1]; return getmin(st[x][l],st[y-pw[l]+1][l]);}LL Ri (LL l,LL r){ LL p=calc(l,r); return a[p]*(p-l+1)+sl[r]-sl[p];}LL Li (LL l,LL r){ LL p=calc(l,r); return a[p]*(r-p+1)+sr[l]-sr[p];}void solve (){ LL l=1,r=1;LL ans=a[1]; for (LL u=1;u<=q;u++) { while (r<s[u].r) ans=ans+Ri(l,++r); while (l<s[u].l) ans=ans-Li(l++,r); while (l>s[u].l) ans=ans+Li(--l,r); while (r>s[u].r) ans=ans-Ri(l,r--); Ans[s[u].id]=ans; } for (LL u=1;u<=q;u++) printf("%lld\n",Ans[u]);}int main(){ scanf("%lld%lld",&n,&q); nn=sqrt(n);for (LL u=1;u<=n;u++) belong[u]=(u-1)/nn+1; for (LL u=1;u<=n;u++) scanf("%lld",&a[u]); for (LL u=1;u<=q;u++) { scanf("%lld%lld",&s[u].l,&s[u].r); s[u].id=u; } sort(s+1,s+1+q,cmp); pre_st(); prepare(); solve(); 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]序列 解题报告
- python模块学习pandas(-)
- java读取、写入保存、遍历ini文件配置数据
- 中文分词
- Eclipse Debug 测试
- Java之多线程死锁-yellowcong
- bzoj4540: [Hnoi2016]序列
- FCN网络的训练——以燃气表数字识别为例
- NOIP2014 DAY1 模拟赛赛后总结
- Navicat for Oracle 提示Cannot load OCI DLL
- [Tyvj P4874]回形遍历
- 多元函数微分法
- select,poll,epoll 区别
- Xcode9 新功能
- 文件处理命令