BZOJ4826: [Hnoi2017]影魔(扫描线+树状数组)

来源:互联网 发布:java设计模式23种分类 编辑:程序博客网 时间:2024/04/28 12:39

传送门

题意:
有n个点,横纵坐标都是1n的排列,每次询问[l,r],求在[l,r]中分别满足一下条件的点对(i,j)
(定义max(l,r)为横坐标lr中纵坐标的最大值)
1.y[i]>max(l,r)y[j]>max(l,r).
2.y[i]>max(l,r)>y[j]y[j]>max(l,r)>y[i]

题解:
离线扫描线+树状数组。

先单调栈找出左右第一个纵坐标大于y[i]L[i],R[i]

首先,对于第一种情况,设有y[i]<y[j]
那么j只能是L[i]或者R[i]
证明:若不是,则两点间有一点纵坐标大于y[i]

对于第二种情况,容易发现所有情况都包含在了对于每个i(L[i],j)(i<j<R[i])或者(j,R[i])(L[i]<j<i)(画一画图就知道了)。

然后把所有合法的点对看做点或者是线段。扫描线一遍即可。

(出题人丧心病狂的卡了线段树,所以学了树状数组的区间加减查询:http://www.cnblogs.com/lcf-2000/p/5866170.html#3773822)

#include<bits/stdc++.h>using namespace std;struct IO{    streambuf *ib,*ob;    int buf[50];    inline void init()    {        ios::sync_with_stdio(false);        cin.tie(NULL);cout.tie(NULL);        ib=cin.rdbuf();ob=cout.rdbuf();    }    inline int read()    {        char ch=ib->sbumpc();int i=0,f=1;        while(!isdigit(ch)){if(ch=='-')f=-1;ch=ib->sbumpc();}        while(isdigit(ch)){i=(i<<1)+(i<<3)+ch-'0';ch=ib->sbumpc();}        return i*f;    }    inline void W(long long x)    {        if(!x){ob->sputc('0');return;}        if(x<0){ob->sputc('-');x=-x;}        while(x){buf[++buf[0]]=x%10,x/=10;}        while(buf[0]){ob->sputc(buf[buf[0]--]+'0');}    }}io;const int Maxn=2e5+50;int n,m,p1,p2,L[Maxn],R[Maxn],K[Maxn];long long ans[Maxn];struct Segment{    int l,r;    Segment(int l,int r):l(l),r(r){}};inline int lowbit(int pos){return pos&(-pos);}struct BIT{    long long d1[Maxn],d2[Maxn];    inline long long asksum(int x)    {        long long res1=0,res2=0;        for(int pos=x;pos;pos-=lowbit(pos))res1+=d1[pos],res2+=d2[pos];        return res1*(x+1)-res2;    }    inline long long query(int l,int r){return asksum(r)-asksum(l-1);}    inline void modify(int l,int r)    {        for(int pos=l;pos<=n;pos+=lowbit(pos))d1[pos]++,d2[pos]+=l;        for(int pos=r+1;pos<=n;pos+=lowbit(pos))d1[pos]--,d2[pos]-=(r+1);    }}t1,t2;struct Q{    int l,r,id,bz;    Q(int l=0,int r=0,int id=0,int bz=0):l(l),r(r),id(id),bz(bz){}};vector<Segment>data2[Maxn];vector<int>data[Maxn];vector<Q>query[Maxn];inline void GetL(int *a){    static int st[Maxn],pos[Maxn],tail;    pos[1]=1,st[1]=K[1];tail=1;    for(int i=2;i<=n;i++)    {        while(st[tail]<K[i]&&tail)a[pos[tail--]]=i;        st[++tail]=K[i],pos[tail]=i;    }    while(tail)a[pos[tail--]]=n+1;}int main(){    io.init();n=io.read(),m=io.read(),p1=io.read(),p2=io.read();    for(int i=1;i<=n;i++)K[i]=io.read();    GetL(R);reverse(K+1,K+n+1);    GetL(L);reverse(L+1,L+n+1);    for(int i=1;i<=n;i++)L[i]=n-L[i]+1;    for(int i=1;i<=n;i++)    {        if(L[i])data[i].push_back(L[i]);        if(R[i]!=n+1)data[i].push_back(R[i]);        if(L[i]&&R[i]>i+1)data2[L[i]].push_back(Segment(i+1,R[i]-1));        if(R[i]!=n+1&&L[i]<i-1)data2[R[i]].push_back(Segment(L[i]+1,i-1));    }    for(int i=1;i<=m;i++)    {        int l=io.read(),r=io.read();l--;        if(l)query[l].push_back(Q(l+1,r,i,-1));        query[r].push_back(Q(l+1,r,i,1));    }    for(int i=1;i<=n;i++)    {        for(int e=data[i].size()-1;e>=0;e--)t1.modify(data[i][e],data[i][e]);        for(int e=data2[i].size()-1;e>=0;e--)t2.modify(data2[i][e].l,data2[i][e].r);        for(int e=query[i].size()-1;e>=0;e--)        {            ans[query[i][e].id]+=1ll*p1*query[i][e].bz*t1.query(query[i][e].l,query[i][e].r);            ans[query[i][e].id]+=1ll*p2*query[i][e].bz*t2.query(query[i][e].l,query[i][e].r);        }    }    for(int i=1;i<=m;i++)io.W(ans[i]),io.ob->sputc('\n');}
原创粉丝点击