[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;
}
当你意识到,每个上一秒都成为永恒。