「AHOI / HNOI2017」影魔
解决这类比较复杂的区间贡献问题关键在于找到计算的对象。
比如这道题,我们计算的对象就是区间中间的最大值。
对于点\(i\),我们找到左边第一个比他大的位置\(L\),以及右边第一个比他大的位置\(R\)。当\(L,R\)同时被询问的区间包含是,\(i\)就会贡献\(p_1\)。当固定左端点为\(L\),右端在\([i+1,R-1]\)之间的时候会贡献\(p_2\);固定右端点\(R\)是同理。还要额外加上\(i,i+1\)贡献的\(p_1\)。
具体实现就可以使用扫描线+树状数组之类的方法。
代码:
#include#define ll long long#define N 200005using namespace std;inline int Get() {int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}while('0'<=ch&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}return x*f;}int n,m;ll p1,p2;int a[N];int L[N],R[N];void pre() { int st[N],top; st[top=0]=0; for(int i=1;i<=n;i++) { while(top&&a[st[top]] =1;i--) { while(top&&a[st[top]] b.l;}bool cmpR(const query &a,const query &b) {return a.r