1. 程式人生 > >luogu P3722 [AH2017/HNOI2017]影魔

luogu P3722 [AH2017/HNOI2017]影魔

傳送門

我太弱了,只會亂搞,正解是不可能正解的,這輩子不可能寫正解的,太蠢了又想不出什麼東西,就是亂搞這種東西,才能維持得了做題這樣子

考慮將詢問離線,按右端點排序,並且預處理出每個位置往前面第一個大於這個數的位置,記為\(fa_i\)

如果加入一個右端點\(i\),那麼可以加上貢獻的左端點有以下三類

  • 在區間\([fa_i,i)\)中,從\(i-1\)開始一直跳\(fa\),能到達的位置加上p1

  • 在區間\([fa_i,i)\)中,從\(i-1\)開始一直跳\(fa\),不能到達的位置加上p2

  • 在區間\([1,fa_i)\)中,從\(fa_i\)開始一直跳\(fa\),能到達的位置加上p2

看下圖把qwq(黑色代表沒加上貢獻,綠色代表加上p1,紅色代表加上p2)

每次移動右端點,對應的詢問答案就是詢問區間內的權值和

程式碼極差,慎看

// luogu-judger-enable-o2
#include<bits/stdc++.h>
#define LL long long
#define il inline
#define re register
#define db double

using namespace std;
const int N=200000+10,M=240000+10;
il int rd()
{
  int x=0,w=1;char ch=0;
  while(ch<'0'||ch>'9') {if(ch=='-') w=-1;ch=getchar();}
  while(ch>='0'&&ch<='9') {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
  return x*w;
}
struct sgmtr
{
#define lc (o<<1)
#define rc ((o<<1)|1)
#define mid ((l+r)>>1)
  LL a[M<<2];
  int lz[M<<2];
  il void psup(int o){a[o]=a[lc]+a[rc];}
  il void ad(int o,int l,int r,int x){a[o]+=1ll*x*(r-l+1),lz[o]+=x;}
  il void psdn(int o,int l,int r)
  {
    if(lz[o]) ad(lc,l,mid,lz[o]),ad(rc,mid+1,r,lz[o]),lz[o]=0;
  }
  void modif(int o,int l,int r,int ll,int rr,int x)
  {
    if(ll<=l&&r<=rr)
      {
        ad(o,l,r,x);
        return;
      }
    psdn(o,l,r);
    if(ll<=mid) modif(lc,l,mid,ll,rr,x);
    if(rr>mid) modif(rc,mid+1,r,ll,rr,x);
    psup(o);
  }
  int quer(int o,int l,int r,int ll,int rr)
  {
    if(ll<=l&&r<=rr) return a[o];
    int an=0;
    psdn(o,l,r);
    if(ll<=mid) an+=quer(lc,l,mid,ll,rr);
    if(rr>mid) an+=quer(rc,mid+1,r,ll,rr);
    psup(o);
    return an;
  }
}tr[2];
int to[N],nt[N],hd[N],tot;
il void add(int x,int y){++tot,to[tot]=y,nt[tot]=hd[x],hd[x]=tot;}
int n,m,p1,p2,a[N],fa[N],top[N];
LL an[N];
void dfs(int x,int ntp)
{
  top[x]=ntp;
  for(int i=hd[x];i;i=nt[i]) dfs(to[i],to[i]==x+1?ntp:to[i]);
}
struct qu
{
  int l,r,id;
  bool operator < (const qu &bb) const {return r<bb.r;}
}qq[N];
int st[N],tp;

int main()
{
  n=rd(),m=rd(),p1=rd(),p2=rd();
  for(int i=1;i<=n;++i)
    {
      a[i]=rd();
      while(tp&&a[st[tp]]<a[i]) --tp;
      fa[i]=st[tp];
      st[++tp]=i;
    }
  for(int i=n;i;--i) add(fa[i],i);
  dfs(0,0);
  for(int i=1;i<=m;++i) qq[i].l=rd(),qq[i].r=rd(),qq[i].id=i;
  sort(qq+1,qq+m+1);
  for(int i=1,r=0;i<=m;++i)
    {
      while(r<qq[i].r)
        {
          ++r;
          tr[1].modif(1,0,n,fa[r],r-1,1);
          int x=r-1;
          while(x)
            {
              tr[0].modif(1,0,n,top[x],x,1);
              tr[1].modif(1,0,n,top[x],x,-1);
              x=fa[top[x]];
            }
          x=fa[fa[r]];
          while(x)
            {
              tr[0].modif(1,0,n,top[x],x,-1);
              tr[1].modif(1,0,n,top[x],x,2);
              x=fa[top[x]];
            }
        }
      int l=qq[i].l;
      an[qq[i].id]=1ll*p1*(tr[0].quer(1,0,n,0,r-1)-tr[0].quer(1,0,n,0,l-1))+1ll*p2*(tr[1].quer(1,0,n,0,r-1)-tr[1].quer(1,0,n,0,l-1));
    }
  for(int i=1;i<=m;++i) printf("%lld\n",an[i]);
  return 0;
}

或者來Orzyyb