[HNOI2017]影魔

题意

一个长度为 n n 的排列,对于一个区间

如果两个端点分别是这个区间的最大值和次大值,有 p1 p 1 的贡献

否则如果其中一个端点是这个区间的最大值,有 p2 p 2 的贡献

q q 次询问一个区间 [L,R] [ L , R ] 所有子区间的贡献和


题解

考虑离线,用单调栈处理每个点 i i 作为最大值的区间 [Li+1,Ri1] [ L i + 1 , R i − 1 ]

1. 1. 区间 [Li,Ri] [ L i , R i ] p1 p 1 的贡献

2.j(Li,i), 2. ∀ j ∈ ( L i , i ) , 区间 [j,Ri] [ j , R i ] p2 p 2 的贡献

3.j(i,Ri), 3. ∀ j ∈ ( i , R i ) , 区间 [Li,j] [ L i , j ] p2 p 2 的贡献

所以我们离线排序处理好,然后扫描线

对于 1, 1 , 扫到 Ri R i 时,更新 Li L i 的贡献

对于 2, 2 , 扫到 Ri R i 时,更新 (Li,i) ( L i , i ) 的贡献

对于 3, 3 , 扫到 Li L i 时,更新 (i,Ri) ( i , R i ) 的贡献

我们对于每个询问 [l,r] [ l , r ] ,在扫到 l1 l − 1 时,我们记录此时区间l到r的每个点的贡献和为 sum1 s u m 1

然后当我们扫到 r r 的时候,再次记录此时的 [l,r] [ l , r ] 的每个点的贡献和为 sum2 s u m 2 ,显然答案就是 sum2sum1 s u m 2 − s u m 1

然后这些东西可以用树状树状维护来维护区间修改和区间和

然后对于每个询问 [l,r] [ l , r ] 一开始还有 (rl)×p1 ( r − l ) × p 1 的贡献,即区间 [l,l+1],[l+1,l+2],,[r1,r] [ l , l + 1 ] , [ l + 1 , l + 2 ] , … , [ r − 1 , r ]

#include
#define fp(i,a,b) for(register int i=a,I=b+1;i
#define fd(i,a,b) for(register int i=a,I=b-1;i>I;--i)
#define go(u) for(register int i=fi[u],v=e[i].to;i;v=e[i=e[i].nx].to)
#define file(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
template<class T>inline bool cmax(T&a,const T&b){return a1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
char ss[1<<17],*A=ss,*B=ss;
inline char gc(){return A==B&&(B=(A=ss)+fread(ss,1,1<<17,stdin),A==B)?-1:*A++;}
template<class T>inline void sd(T&x){
    char c;T y=1;while(c=gc(),(c<48||571)if(c==45)y=-1;x=c-48;
    while(c=gc(),4758)x=x*10+c-48;x*=y;
}
char sr[1<<21],z[20];int C=-1,Z;
inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
template<class T>inline void we(T x){
    if(C>1<<20)Ot();if(x<0)sr[++C]=45,x=-x;
    while(z[++Z]=x%10+48,x/=10);
    while(sr[++C]=z[Z],--Z);sr[++C]='\n';
}
const int N=2e5+5,M=2.5*N;
typedef long long ll;
typedef int arr[N];
struct da{int l,r,x,w,id;}s1[M],s2[M];
int n,m,cnt,p1,p2;arr k,q,L,R;ll ans[N],c1[N],c2[N];
inline void mdy(int x,int w){for(int i=x;i<=n;i+=i&-i)c1[i]+=w,c2[i]+=(ll)x*w;}
inline ll qry(int x){ll w=0;for(int i=x;i;i-=i&-i)w+=(ll)(x+1)*c1[i]-c2[i];return w;}
inline bool cmp(const da&a,const da&b){return a.xint main(){
    #ifndef ONLINE_JUDGE
        file("s");
    #endif
    sd(n);sd(m);sd(p1),sd(p2);
    fp(i,1,n)sd(k[i]);
    int top=0;q[++top]=0,k[0]=k[n+1]=n+1;
    fp(i,1,n+1){
        while(k[q[top]]1,n){
        if(L[i]&&R[i]<=n)s2[++cnt]={L[i],L[i],R[i],p1};
        if(L[i]&&i+11,R[i]-1,L[i],p2};
        if(L[i]+11,i-1,R[i],p2};
    }int x,y;
    fp(i,1,m){
        sd(x),sd(y);ans[i]=(y-x)*p1;
        s1[i]={x,y,x-1,-1,i},s1[i+m]={x,y,y,1,i};
    }
    sort(s1+1,s1+2*m+1,cmp);sort(s2+1,s2+cnt+1,cmp);
    x=1,y=1;while(!s1[x].x)++x;
    for(int i=1;x<=2*m&&i<=n;++i){
        for(;y<=cnt&&s2[y].x==i;++y)
            mdy(s2[y].l,s2[y].w),
            mdy(s2[y].r+1,-s2[y].w);
        for(;x<=2*m&&s1[x].x==i;++x)
            ans[s1[x].id]+=s1[x].w*(qry(s1[x].r)-qry(s1[x].l-1));
    }
    fp(i,1,m)we(ans[i]);
return Ot(),0;
}

都快HNOI2018才过来写这题我是不是要完了qwq

你可能感兴趣的:(树状数组)