[HNOI2017]影魔

题解:

这个题可以采取离线处理的方式.先处理出每个点i左边第一个比它大的点L[i],和右边第一个比它大的点R[i].
那么对于区间L[i]到R[i]有p1的贡献.①
对于左端点在L[i]+1到i-1,右端点为R[i]的区间有p2的贡献.②
对于左端点为L[i],右端点为i+1到R[i]-1的区间也有p2的贡献.③
所以我们离线排序处理好.
对于①情况,我们在扫到R[i]时,更新点L[i]的贡献
对于②情况,我们在扫到R[i]时,更新区间L[i]+1到i-1的贡献
对于③情况,我们在扫到L[i]时,更新区间i+1到R[i]-1的贡献
我们对于每个询问[l,r],在扫到l-1时,我们记录此时区间l到r的每个点的贡献和为sum1,然后当我们扫到r的时候,再次记录此时的区间l到r的每个点的贡献和为sum2,显然答案就是sum2-sum1了.

 

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstdlib>
 4 #include<algorithm>
 5 #include<cmath>
 6 #include<cstring>
 7 #include<queue>
 8 #include<vector>
 9 #include<set>
10 #define RG register
11 #define LL long long int
12 #define MAXN 500010
13 using namespace std;
14 const int INF=1e9;
15 struct node{
16   int l,r,x,id,v;
17   node(){}
18   node(int l_,int r_,int x_,int id_,int v_):l(l_),r(r_),x(x_),id(id_),v(v_){}
19   bool operator <(const node &tmp)const{
20     return x<tmp.x;
21   }
22 }s1[MAXN],s2[MAXN];
23 int n,m,p1,p2;
24 int k[MAXN],q[MAXN],top;
25 int L[MAXN],R[MAXN];
26 LL ans[MAXN],c1[MAXN],c2[MAXN];
27 int lowbit(int x)
28 {
29   return x&(-x);
30 }
31 void add(int x,int y)//区间修改操作
32 {
33   if(x) for(int i=x;i<=n;i+=lowbit(i)) c1[i]+=y,c2[i]+=(LL)x*y;
34 }
35 LL sum(int x)
36 {
37   LL num=0;
38   for(int i=x;i>0;i-=lowbit(i)) num+=(x+1)*c1[i]-c2[i];
39   return num;
40 }
41 int main()
42 {
43   freopen("1.in","r",stdin);
44   scanf("%d%d%d%d",&n,&m,&p1,&p2);
45   k[0]=k[n+1]=n+1;q[++top]=0;
46   for(int i=1;i<=n;i++) scanf("%d",&k[i]);
47   for(int i=1;i<=n+1;i++)
48     {
49       while(k[q[top]]<k[i]) R[q[top]]=i,top--;
50       L[i]=q[top];q[++top]=i;
51     }
52   int x,y;
53   for(int i=1;i<=m;i++)
54     {
55       scanf("%d%d",&x,&y);ans[i]+=(y-x)*p1;
56       s1[i]=node(x,y,x-1,i,-1);s1[i+m]=node(x,y,y,i,1);
57     }
58   sort(s1+1,s1+2*m+1);int tot=0;
59   for(int i=1;i<=n;i++)
60     {
61       if(1<=L[i]&&R[i]<=n) s2[++tot]=node(L[i],L[i],R[i],0,p1);
62       if(1<=L[i]&&R[i]>i+1) s2[++tot]=node(i+1,R[i]-1,L[i],0,p2);
63       if(L[i]+1<i&&R[i]<=n) s2[++tot]=node(L[i]+1,i-1,R[i],0,p2);
64     }
65   sort(s2+1,s2+tot+1);int n1=1,n2=1;
66   while(!s1[n1].x) n1++;
67   for(int i=1;n1<=m*2&&i<=n;i++)
68     {
69       while(n2<=tot&&s2[n2].x==i){
70     add(s2[n2].r+1,-s2[n2].v);
71     add(s2[n2].l,s2[n2].v);
72     n2++;
73       }
74       while(n1<=m*2&&s1[n1].x==i){
75     ans[s1[n1].id]+=s1[n1].v*(sum(s1[n1].r)-sum(s1[n1].l-1));
76     n1++;
77       } 
78     }
79   for(int i=1;i<=m;i++) printf("%lld\n",ans[i]);
80   return 0;
81 }

 

posted @ 2017-12-21 17:45  楼主大大  阅读(166)  评论(0编辑  收藏  举报