码迷,mamicode.com
首页 > 其他好文 > 详细

bzoj4826[hnoi2017]影魔

时间:2018-06-10 15:25:07      阅读:130      评论:0      收藏:0      [点我收藏+]

标签:clu   cdb   span   题解   题意   关系   pen   \n   std   

题意:每次询问一个区间[l,r],问[l,r]中的每一对(i,j)能够贡献多少总加成?给定序列a是1~n的一个排列,也就是a[i]两两不同。

设z=max{a[i+1],a[i+2],...,a[j-1]},若z<min(a[i],a[j]),加成p1;若min(a[i],a[j])<z<max(a[i],a[j]),加成p2。n<=20W。

 

标程:

技术分享图片
 1 #include<bits/stdc++.h>
 2 #define mid ((l+r)>>1)
 3 #define P pair<int,ll>
 4 #define fir first
 5 #define sec second
 6 using namespace std;
 7 typedef long long ll;
 8 int read()
 9 {
10    int x=0,f=1;char ch=getchar();
11    while (ch<0||ch>9) {if (ch==-) f=-1;ch=getchar();}
12    while (ch>=0&&ch<=9) x=(x<<1)+(x<<3)+ch-0,ch=getchar();
13    return x*f;
14 }
15 const int N=200005;
16 int rt1[N],rt2[N],sc,num[N*40],ls[N*40],rs[N*40],n,m,lf[N],rg[N],p1,p2,top,a[N],q[N];
17 ll sum[N*40];
18 P operator + (P a,P b) {return P(a.fir+b.fir,a.sec+b.sec);}
19 void ins(int &k,int pk,int l,int r,int x)
20 {
21     k=++sc;ls[k]=ls[pk];rs[k]=rs[pk];
22     if (l==r) {sum[k]=sum[pk]+x;num[k]=num[pk]+1;return;}
23     if (x<=mid) ins(ls[k],ls[pk],l,mid,x);
24     else ins(rs[k],rs[pk],mid+1,r,x);
25     sum[k]=sum[ls[k]]+sum[rs[k]];
26     num[k]=num[ls[k]]+num[rs[k]];
27 }
28 P qry(int k1,int k2,int l,int r,int L,int R)
29 {
30     if (!k1) return P(0,0);//if(!k2)跳出P(num[k1],sum[k1])是不行的,考虑区间要在[L,R]内 
31     if (L<=l&&r<=R) return P(num[k1]-num[k2],sum[k1]-sum[k2]);
32     P res=P(0,0);
33     if (L<=mid) res=res+qry(ls[k1],ls[k2],l,mid,L,R);
34     if (R>mid) res=res+qry(rs[k1],rs[k2],mid+1,r,L,R);
35     return res;
36 }
37 int main()
38 {
39     n=read();m=read();p1=read();p2=read();
40     for (int i=1;i<=n;i++) a[i]=read();
41     for (int i=1;i<=n;i++)
42     {
43         while (top>=1&&a[i]>a[q[top]]) top--;
44         lf[i]=q[top];q[++top]=i;
45     }
46     q[top=0]=n+1;
47     for (int i=n;i>=1;i--)
48     {
49         while (top>=1&&a[i]>a[q[top]]) top--;
50         rg[i]=q[top];q[++top]=i;
51     }
52     for (int i=1;i<=n;i++) 
53         ins(rt1[i],rt1[i-1],0,n+1,lf[i]),ins(rt2[i],rt2[i-1],0,n+1,rg[i]);
54     while (m--)
55     {
56         int l,r;
57         l=read();r=read();
58         P z1=qry(rt1[r],rt1[l-1],0,n+1,l,n);
59         P z2=qry(rt2[r],rt2[l-1],0,n+1,1,r);
60         ll x1=z1.fir+z2.fir;
61         ll x2=z2.sec-z1.sec+(ll)(r+1)*(r-l+1-z2.fir)-(ll)(l-1)*(r-l+1-z1.fir)-2*(r-l+1);
62         printf("%lld\n",(ll)p1*x1+(ll)p2*(x2-x1));
63     }
64    return 0;
65 }
View Code

 

题解:计数+主席树

一开始卡在没有意识到计数时可以通过设置大小关系做到不重,一个区间只用统计到一个端点。

设[l,r]区间中满足限制1的有x1个,设满足z<max(a[i],a[j])限制2的有x2个(这样转化比较好求)。最后答案是x1*p1+(x2-x1)*p2。

考虑构造统计方式:对于每一个位置求出lf[i]和rg[i]表示左右离i位置最近的比它大的位置。

限制1:设i位置为较小端点,满足条件的端点只有lf[i]和rg[i]。式子:$\sum_{i=l}^{r}[lf[i]>=l]+[rg[i]<=r]$。

限制2:设i位置为较大端点,满足条件的是(lf[i],i)∪(i,rg[i])。式子:$\sum_{i=l}^{r}(min(rg[i],r+1)-max(lf[i],l-1)-2)$。权值主席树计算。

bzoj4826[hnoi2017]影魔

标签:clu   cdb   span   题解   题意   关系   pen   \n   std   

原文地址:https://www.cnblogs.com/Scx117/p/9162659.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!