Portal --> bzoj4826

Solution

  为什么莫名读了很长时间的题。。。== 逐渐不会语文qwq

  貌似这题的做法很多,丢上来的话是因为。。这个化简条件的过程莫名爽哈哈哈哈哈

  注意到因为\(k\)是一个排列,所以不存在等于的情况,那么其实把两个条件都化简一下(其实也不是化简就是用简单一点的语言写出来)就是:

  对于一个点对\((i,j)\)(\(i<j\)),我们用\(mx\)表示\(k[i+1]...k[j-1]\)的最大值,那么如果满足\(mx<k[i]\)&&\(mx<k[j]\)则有\(p1\)的贡献,如果满足\(k[i]<mx<k[j]\)或者\(k[j]<mx<k[i]\)则有\(p2\)的贡献

  至于这个\(k[i]\)和\(k[j]\)谁大谁小的问题。。我们其实完全可以正着统计一次\(k[i]<mx<k[j]\)再把整个数组反过来,然后把询问也反过来再统计一次

  所以现在就变成了求\(mx<k[i]\)&&\(mx<k[j]\)的情况以及\(k[i]<mx<k[j]\)的情况

  再冷静思考一下就会发现,其实也就是说当\(k[i]\)为该区间的最大值的时候,\(k[j]\)为次大值则有\(p1\)的贡献,\(k[j]\)不为次大值的时候则是\(p2\)的贡献,否则(也就是\(k[i]\)不是区间最大值)没有贡献

  那这样一来问题就很好办了

  

  考虑离线做法

​  大体的思路是,我们对于每一个\(k[i]\),将所有满足\([i,j]\)中最大值为\(k[i]\)的\(j\)处的贡献\(+p2\),然后再单独将\(k[j]\)为次大值的\(j\)处的贡献\(-p2+p1\),注意到需要\(+p2\)的位置一定是一个区间,而次大值的那个区间是唯一的,所以我们可以考虑用一棵线段树维护一下区间右端点在每个位置的贡献(其实还是套路想法:固定左端点,考虑右端点在哪些位置有贡献)

​  再具体一点就是,首先预处理出每个\(k[i]\)后面的第一个\(>k[i]\)的位置(记为\(nxt[i]\)),然后我们将所有的询问按照左端点从大到小排序,依次处理,每次将还没有统计的满足\(i>=\)当前询问左端点的区间的贡献进行统计,统计的方式就是线段树对\([i+1,nxt[i]-1]\)区间\(+p2\),再对\(nxt[i]\)这个位置单点\(-p2+p1\),然后对于每个询问\((l,r)\)查询\([l+1,r]\)即可

  然后我们再把数组什么的反过来再重复一遍上面的步骤就好了

  这里有一个比较好玩的地方:就是比如说我们在从左往右处理(就是第一遍计算)的时候,对\(nxt[i]\)这个位置单点\(-p2+p1\)时减去的那个\(p2\)其实应该是在从右往左处理(将数组反过来之后第二遍计算)的时候才会被加到的,相对的第二遍计算的时候减去的那个\(p2\)是在第一次计算的时候加上的,具体的话就是因为。。只有确定了次大值才能比较方便地确定最大值,所以我们对\(nxt[i]\)单点修改的处理其实是将\(k[i]\)看成次大值将\(k[nxt[i]]\)看成最大值,然后计算\([i,nxt[i]]\)这个区间的贡献

  

  如果在线做法的话。。应该可持久化就好了吧qwq

  

​  代码大概长这个样子

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstring>
  4. #include<algorithm>
  5. #define ll long long
  6. using namespace std;
  7. const int N=2*(1e5)+10;
  8. int n,m,p1,p2,top;
  9. struct Q{
  10. int l,r,id;
  11. void rev(){l=n-l+1; r=n-r+1; swap(l,r);}
  12. friend bool operator < (Q x,Q y){return x.l>y.l;}
  13. }q[N];
  14. namespace Seg{/*{{{*/
  15. const int N=::N*4;
  16. int ch[N][2];
  17. ll sum[N],tag[N];
  18. int n,tot;
  19. void pushup(int x,int l,int r){
  20. int mid=l+r>>1;
  21. sum[x]=sum[ch[x][0]]+tag[ch[x][0]]*(mid-l+1)+sum[ch[x][1]]+tag[ch[x][1]]*(r-mid);
  22. }
  23. void _build(int x,int l,int r){
  24. sum[x]=0; tag[x]=0;
  25. if (l==r) return;
  26. int mid=l+r>>1;
  27. ch[x][0]=++tot; _build(ch[x][0],l,mid);
  28. ch[x][1]=++tot; _build(ch[x][1],mid+1,r);
  29. }
  30. void build(int _n){n=_n; tot=1; _build(1,1,n);}
  31. void _update(int x,int l,int r,int lx,int rx,ll delta){
  32. if (l<=lx&&rx<=r){tag[x]+=delta; return;}
  33. int mid=lx+rx>>1;
  34. if (r<=mid) _update(ch[x][0],l,r,lx,mid,delta);
  35. else if (l>mid) _update(ch[x][1],l,r,mid+1,rx,delta);
  36. else{
  37. _update(ch[x][0],l,mid,lx,mid,delta);
  38. _update(ch[x][1],mid+1,r,mid+1,rx,delta);
  39. }
  40. pushup(x,lx,rx);
  41. }
  42. void update(int l,int r,ll delta){if (l<=r) _update(1,l,r,1,n,delta);}
  43. ll _query(int x,int l,int r,int lx,int rx,ll tg){
  44. tg+=tag[x];
  45. if (l<=lx&&rx<=r) return sum[x]+tg*(r-l+1);
  46. int mid=lx+rx>>1;
  47. if (r<=mid) return _query(ch[x][0],l,r,lx,mid,tg);
  48. else if (l>mid) return _query(ch[x][1],l,r,mid+1,rx,tg);
  49. else
  50. return _query(ch[x][0],l,mid,lx,mid,tg)+_query(ch[x][1],mid+1,r,mid+1,rx,tg);
  51. }
  52. ll query(int l,int r){return l<=r?_query(1,l,r,1,n,0):0;}
  53. }/*}}}*/
  54. int nxt[N],st[N],K[N];
  55. ll ans[N];
  56. void get_nxt(){
  57. top=0;
  58. for (int i=1;i<=n;++i) nxt[i]=n+1;
  59. for (int i=1;i<=n;++i){
  60. while (top&&K[st[top]]<K[i]) nxt[st[top--]]=i;
  61. st[++top]=i;
  62. }
  63. }
  64. void solve(){
  65. sort(q+1,q+1+m);
  66. Seg::build(n+1);
  67. int now=n;
  68. for (int i=1;i<=m;++i){
  69. while (now>=q[i].l){
  70. Seg::update(now+1,nxt[now]-1,p2);
  71. Seg::update(nxt[now],nxt[now],-p2+p1);
  72. --now;
  73. }
  74. ans[q[i].id]+=Seg::query(q[i].l+1,q[i].r);
  75. }
  76. }
  77. int main(){
  78. #ifndef ONLINE_JUDGE
  79. freopen("a.in","r",stdin);
  80. #endif
  81. scanf("%d%d%d%d",&n,&m,&p1,&p2);
  82. for (int i=1;i<=n;++i) scanf("%d",K+i);
  83. for (int i=1;i<=m;++i)
  84. scanf("%d%d",&q[i].l,&q[i].r),q[i].id=i;
  85. get_nxt();
  86. solve();
  87. reverse(K+1,K+1+n);
  88. for (int i=1;i<=m;++i) q[i].rev();
  89. get_nxt();
  90. solve();
  91. for (int i=1;i<=m;++i) printf("%lld\n",ans[i]);
  92. }

【bzoj4826】影魔的更多相关文章

  1. [BZOJ4785][ZJOI2017]树状数组(概率+二维线段树)

    4785: [Zjoi2017]树状数组 Time Limit: 40 Sec  Memory Limit: 512 MBSubmit: 297  Solved: 195[Submit][Status ...

  2. 【BZOJ4826】【HNOI2017】影魔(扫描线,单调栈)

    [BZOJ4826][HNOI2017]影魔(扫描线,单调栈) 题面 BZOJ 洛谷 Description 影魔,奈文摩尔,据说有着一个诗人的灵魂.事实上,他吞噬的诗人灵魂早已成千上万.千百年来,他 ...

  3. 【BZOJ4826】[Hnoi2017]影魔 单调栈+扫描线

    [BZOJ4826][Hnoi2017]影魔 Description 影魔,奈文摩尔,据说有着一个诗人的灵魂.事实上,他吞噬的诗人灵魂早已成千上万.千百年来,他收集了各式各样的灵魂,包括诗人.牧师.帝 ...

  4. [bzoj4826][Hnoi2017]影魔_单调栈_主席树

    影魔 bzoj-4826 Hnoi-2017 题目大意:给定一个$n$个数的序列$a$,求满足一下情况的点对个数: 注释:$1\le n,m\le 2\cdot 10^5$,$1\le p1,p2\l ...

  5. bzoj4826 [Hnoi2017]影魔

    Description 影魔,奈文摩尔,据说有着一个诗人的灵魂.事实上,他吞噬的诗人灵魂早已成千上万.千百年来,他收集了各式各样的灵魂,包括诗人.牧师.帝王.乞丐.奴隶.罪人,当然,还有英雄.每一个灵 ...

  6. bzoj千题计划196:bzoj4826: [Hnoi2017]影魔

    http://www.lydsy.com/JudgeOnline/problem.php?id=4826 吐槽一下bzoj这道题的排版是真丑... 我还是粘洛谷的题面吧... 提供p1的攻击力:i,j ...

  7. [BZOJ4826][HNOI2017]影魔(主席树)

    4826: [Hnoi2017]影魔 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 669  Solved: 384[Submit][Status][ ...

  8. BZOJ4826 [Hnoi2017]影魔 【线段树 + 单调栈】

    题目链接 BZOJ4826 题解 蒟蒻智力水平捉急orz 我们会发现相邻的\(i\)和\(j\)贡献一定是\(p1\),可以很快算出来[然而我一开始忘了考虑调了半天] 我们现在只考虑不相邻的 我们只需 ...

  9. 刷题总结——影魔(HNOI2017 BZOJ4826 线段树+扫描线)

    题目: Description 影魔,奈文摩尔,据说有着一个诗人的灵魂.事实上,他吞噬的诗人灵魂早已成千上万.千百年来,他收集了各式各样 的灵魂,包括诗人.牧师.帝王.乞丐.奴隶.罪人,当然,还有英雄 ...

随机推荐

  1. Ruby知识点一:方法

    1.实例方法 接收者是对象本身的方法 2.类方法 接收者是类本身的方法,调用类方法时,可以使用::或者.两个符号. 类名.方法名 类名::方法名 3.函数式方法 没有接收者(接收者省略而已)的方法 4 ...

  2. 【每日scrum】第一次冲刺day3

    学习安卓,和小伙伴讨论百度API调用的问题,最后决定自己写地图

  3. web09 struts2配置 struts2入门

    电影网站:www.aikan66.com 项目网站:www.aikan66.com游戏网站:www.aikan66.com图片网站:www.aikan66.com书籍网站:www.aikan66.co ...

  4. Sprint9

    进展:完善设置事件提醒界面,增加调用手机铃声部分,以及是否选择振动,以及可以添加事件进行保存.

  5. 编写了几个Java类,但是一直运行某一个class,这种是因为:main方法写错

    编写了几个Java类,但是一直运行某一个class,这种是因为:main方法写错

  6. 编程之法section II: 2.2 和为定值的两个数

    ====数组篇==== 2.2 求和为定值的两个数: 题目描述:有n个整数,找出其中满足两数相加为target的两个数(如果有多组满足,只需要找出其中一组),要求时间复杂度尽可能低. 解法一: 思路: ...

  7. linshi18

    #include<iostream> using namespace std; int n,m,k; #define max 100 char mmap[max][max]; int mm ...

  8. HDU 4514 湫湫系列故事——设计风景线 树的直径

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4514 湫湫系列故事--设计风景线 Time Limit: 5000/2000 MS (Java/Ot ...

  9. Team饭来了团队作业3需求改进与系统设计

    团队名称:饭来了 人员组成: 队长:侯晓东          学号:2016012087 队员:崔啸寒          学号:2016012006 队员:方柱权          学号:201601 ...

  10. C#代码分析(第三周)

    阅读下面程序,请回答如下问题: 问题1:这个程序要找的是符合什么条件的数? 问题2:这样的数存在么?符合这一条件的最小的数是什么? 问题3:在电脑上运行这一程序,你估计多长时间才能输出第一个结果?时间 ...