[AH2017/HNOI2017]影魔

传送门

题面涉嫌抄袭dota2

这个题好巧妙啊……
首先我们预处理出对于每个点,在它左边和右边最靠近他的并且大于它的点在哪,这个可以用单调栈做。小声bb一句其实这玩意也可以用主席树,值域这么小是为这个准备的?
然后每个\(l[i],r[i]\)会产生一个p1的贡献,而对于\(l[i]\),在\([i+1,r[i]-1]\)区间中的点每个都会产生一个p2的贡献,对于\(r[i]\),在\([l[i]+1,i-1]\)中每个点会产生一个p2的贡献.
啊,然后我们就可以离线去做了……每次在扫到\(l[i],r[i]\)的时候对应的在线段树上进行修改……
然后我们把每个询问区间都离线下来,对于每个区间\([l,r]\),在扫到l-1的时候,我们减去当前这段区间的值,在扫到r的时候再加上,就可以得到这段区间的答案了。

借用老詹的话,区间排序用啥排序,用vector存下来是真的爽。

#include<bits/stdc++.h>
#define rep(i,a,n) for(int i = a;i <= n;i++)
#define per(i,n,a) for(int i = n;i >= a;i--)
#define enter putchar('\n')
#define pr pair<int,int>
#define mp make_pair
#define fi first
#define sc second
#define pb push_back

using namespace std;
typedef long long ll;
const int M = 200005;
const int mod = 1e9+7;

ll read()
{
   ll ans = 0,op = 1;char ch = getchar();
   while(ch < '0' || ch > '9') {if(ch == '-') op = -1;ch = getchar();}
   while(ch >='0' && ch <= '9') ans = ans * 10 + ch - '0',ch = getchar();
   return ans * op;
}

struct tree
{
   ll sum,lazy;
}t[M<<2];

struct dot
{
   ll l,r;
}d[M<<1];

struct node
{
   int id,fla;
};

vector<node> v[M],q[M];
ll n,m,p1,p2,k[M],sta[M],top,l,r,ans[M];

void init()
{
   rep(i,1,n)
   {
      while(top && k[sta[top]] < k[i]) top--;
      d[i].l = sta[top],sta[++top] = i;
   }
   top = 0,sta[top] = n + 1;
   per(i,n,1)
   {
      while(top && k[sta[top]] < k[i]) top--;
      d[i].r = sta[top],sta[++top] = i;
   }
   rep(i,1,n) v[d[i].l].pb((node){i,0}),v[d[i].r].pb((node){i,1});
}

void pushdown(int p,int l,int r)
{
   int mid = (l+r) >> 1;
   if(t[p].lazy)
   {
      t[p<<1].lazy += t[p].lazy,t[p<<1|1].lazy += t[p].lazy;
      t[p<<1].sum += t[p].lazy * (mid - l + 1);
      t[p<<1|1].sum += t[p].lazy * (r - mid);
      t[p].lazy = 0;
   }
}

void modify(int p,int l,int r,int kl,int kr,ll val)
{
   if(kl > kr) return;
   if(l == kl && r == kr) {t[p].sum += val * (r - l + 1),t[p].lazy += val;return;}
   int mid = (l+r) >> 1;
   pushdown(p,l,r);
   if(kr <= mid) modify(p<<1,l,mid,kl,kr,val);
   else if(kl > mid) modify(p<<1|1,mid+1,r,kl,kr,val);
   else modify(p<<1,l,mid,kl,mid,val),modify(p<<1|1,mid+1,r,mid+1,kr,val);
   t[p].sum = t[p<<1].sum + t[p<<1|1].sum;
}

ll query(int p,int l,int r,int kl,int kr)
{
   if(l == kl && r == kr) return t[p].sum;
   int mid = (l+r) >> 1;
   pushdown(p,l,r);
   if(kr <= mid) return query(p<<1,l,mid,kl,kr);
   else if(kl > mid) return query(p<<1|1,mid+1,r,kl,kr);
   else return query(p<<1,l,mid,kl,mid) + query(p<<1|1,mid+1,r,mid+1,kr);
}

int main()
{
   n = read(),m = read(),p1 = read(),p2 = read();
   rep(i,1,n) k[i] = read();
   init();
   rep(i,1,m)
   {
      l = read(),r = read(),d[i + n] = (dot){l,r};
      q[l-1].pb((node){i,-1}),q[r].pb((node){i,1});
   }
   rep(i,1,n)
   {
      rep(j,0,(int)v[i].size()-1)
      {
	 int cur = v[i][j].id,fla = v[i][j].fla;
	 if(!fla) modify(1,1,n,cur+1,d[cur].r-1,p2);
	 else
	 {
	    if(d[cur].l) modify(1,1,n,d[cur].l,d[cur].l,p1);
	    modify(1,1,n,d[cur].l+1,cur-1,p2);
	 }  
      }
      rep(j,0,(int)q[i].size()-1)
      {
	 int cur = q[i][j].id;
	 ans[cur] += query(1,1,n,d[cur+n].l,d[cur+n].r) * q[i][j].fla;
      }
   }
   rep(i,1,m) ans[i] += p1 * (d[i+n].r - d[i+n].l);
   rep(i,1,m) printf("%lld\n",ans[i]);
   return 0;
}

posted @ 2019-03-26 23:30  CaptainLi  阅读(224)  评论(0编辑  收藏  举报