bzoj4826 [Hnoi2017]影魔

92 篇文章 1 订阅
18 篇文章 0 订阅

分析:直接贴题解了:
对每个点i,单调栈求出左边和右边第一个大于i的位置,记为l[i]和r[i]
那么(l[i],r[i])会产生p1的贡献
左端点为l[i],右端点在[i+1,r-1]的点对都会产生p2的贡献(原来题解笔误了)
右端点为r[i],左端点在[l+1,i-1]的点对都会产生p2的贡献
将点对看成平面上的点,横坐标左端点纵坐标右端点,上述贡献分别对应单点加(p1)和线段加(p2)
查询就是矩形求和
主席树开两颗维护一下就好,注意把相同的横坐标的用模拟链表存一下。
所以。。这题千万要注意程序常数啊!!!!!!!!!!!!我日,主席树被卡翻了,被卡了一个下午,把所有的define全部换回去加上快速读入才能过。。。出题人你要这样??(╯‵□′)╯︵┻━┻
ccz大爷的笛卡尔树+扫描线速度快,码量少,艹飞主席树,然而我并不会打笛卡尔(╯‵□′)╯︵┻━┻

#include<iostream>  
#include<cstring>  
#include<cmath>  
#include<algorithm>   
#include<cstdio>  
using namespace std;  
#define N 200010  
#define M 20000010  
using namespace std;
typedef long long ll;
struct node
{   
    int l,r,v;    
}t[N*4];  
int head[N],cnt;  
int n,m,p1,p2;  
int a[N];  
ll v[M],key[M];  
int stack[N],top;
int from[N*4];
int lson[M],rson[M],l[N],r[N],Left[N],Right[N];  
int tot;  
inline int read()
{
    int k=0;
    char f=1;
    char c=getchar();
    for(;!isdigit(c);c=getchar() )
        if(c=='-')
            f=-1;
    for(;isdigit(c);c=getchar() )
        k=k*10+c-'0';
    return k*f;
}
inline void add(int x,int l,int r,int v){  
    from[++cnt]=head[x];  
    head[x]=cnt;  
    t[cnt].l=l;  
    t[cnt].r=r;  
    t[cnt].v=v;  
}  
inline void change(int &x,int last,int l1,int r1,int l,int r,int val)
{  
    if(l>r) return ;  
    x=++tot;  
    v[x]=v[last];  
    key[x]=key[last];  
    lson[x]=lson[last];
    rson[x]=rson[last];
    v[x]+=1ll*(r-l+1)*val;  
    if(l1==l&&r1==r)
    {  
        key[x]+=val;  
        return ;  
    }  
    int mid=(l1+r1)>>1;  
    if(r<=mid)  
    change(lson[x],lson[last],l1,mid,l,r,val);  
    else if(l>mid) 
    change(rson[x],rson[last],mid+1,r1,l,r,val);  
    else  
    change(lson[x],lson[last],l1,mid,l,mid,val), 
    change(rson[x],rson[last],mid+1,r1,mid+1,r,val);  

}  
ll query(int x,int l1,int r1,int l,int r){  
    if(!x){  
        return 0;  
    }  
    if(l1==l&&r1==r){  
        return v[x];  
    }  
    ll ans=key[x]*(r-l+1);  
    int mid=l1+r1>>1;  
    if(r<=mid)  return ans+query(lson[x],l1,mid,l,r);  
    else if(l>mid)return ans+query(rson[x],mid+1,r1,l,r);  
    else return ans+query(lson[x],l1,mid,l,mid)+query(rson[x],mid+1,r1,mid+1,r);    
}  
int main()
{  
    freopen("sf.in","r",stdin);
    freopen("sf.out","w",stdout);
    n=read();m=read();  
    p1=read();p2=read();  
    int i;
    for(i=1;i<=n;i++)  
        a[i]=read();      
    for(i=1;i<=n;i++)
    {  
        while(top&&a[stack[top]]<a[i])top--;  
        l[i]=stack[top]+1;  
        stack[++top]=i;  
    }  
    stack[top=0]=n+1;  
    for(i=n;i;i--)
    {  
        while(top&&a[stack[top]]<a[i])top--;   
        r[i]=stack[top]-1;  
        stack[++top]=i;  
    }  
    for(i=1;i<=n;i++)
    {  
        add(l[i]-1,r[i]+1,r[i]+1,p1);  
        add(l[i]-1,i+1,r[i],p2);  
        add(r[i]+1,l[i],i-1,p2);  
    }  
    int x;
    for(x=1;x<=n;x++)
    {  
        Left[x]=Left[x-1];  
        for(i=head[x];i;i=from[i]) 
        if(t[i].l>x) change(Left[x],Left[x],1,n,max(1,t[i].l),min(n,t[i].r),t[i].v);  
        if(x!=n)change(Left[x],Left[x],1,n,x+1,x+1,p1);       
    }  
    for(x=n;x;x--)
    {  
        Right[x]=Right[x+1];  
        for(i=head[x];i;i=from[i])
            if(t[i].r<x)change(Right[x],Right[x],1,n,max(1,t[i].l),min(n,t[i].r),t[i].v);  
    }  
    while(m--)
    {  
        int x,y;
        x=read();y=read();  
        ll ans=0;  
        ans+=query(Left[y],1,n,x,y);  
        ans-=query(Left[x-1],1,n,x,y);  
        ans+=query(Right[x],1,n,x,y);  
        ans-=query(Right[y+1],1,n,x,y);  
        printf("%lld\n",ans);  
    }  
    return 0;  
}  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值