Description
给定长度为n的序列:a1,a2,…,an,记为a[1:n]。类似地,a[l:r](1≤l≤r≤N)是指序列:al,al+1,…,ar-
1,ar。若1≤l≤s≤t≤r≤n,则称a[s:t]是a[l:r]的子序列。现在有q个询问,每个询问给定两个数l和r,1≤l≤r
≤n,求a[l:r]的不同子序列的最小值之和。例如,给定序列5,2,4,1,3,询问给定的两个数为1和3,那么a[1:3]有
6个子序列a[1:1],a[2:2],a[3:3],a[1:2],a[2:3],a[1:3],这6个子序列的最小值之和为5+2+4+2+2+2=17。
Input
输入文件的第一行包含两个整数n和q,分别代表序列长度和询问数。接下来一行,包含n个整数,以空格隔开
,第i个整数为ai,即序列第i个元素的值。接下来q行,每行包含两个整数l和r,代表一次询问。
Output
对于每次询问,输出一行,代表询问的答案。
Sample Input
5 5
5 2 4 1 3
1 5
1 3
2 4
3 5
2 5
Sample Output
28
17
11
11
17
HINT
1 ≤N,Q ≤ 100000,|Ai| ≤ 10^9
Source
这破题网上其他人的题解都是莫队,就看到整个提交区里全是写莫队的,我也是醉了
有nlogn的线段树做法,做法同4262
4262的题解可以去Claris博客找
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define LL long long
#define MAXN 100010
#define P 1000000000
#define GET (ch>='0'&&ch<='9')
#define lchild rt<<1,l,mid
#define rchild rt<<1|1,mid+1,r
#define ln rt<<1
#define rn rt<<1|1
using namespace std;
inline void in(int &x)
{
char ch=getchar();x=0;int flag=1;
while (!GET) flag=ch=='-'?-1:1,ch=getchar();
while (GET) x=x*10+ch-'0',ch=getchar();x*=flag;
}
int n,m,l1,r1,l2,r2,cnt;
int a[MAXN];
LL ans[MAXN];
int sta[MAXN],top;
struct node
{
LL a,b,c,d;
node() { a=1;b=c=d=0; }
node(LL _a,LL _b,LL _c,LL _d) { a=_a;b=_b;c=_c;d=_d; }
inline bool check() { return a!=1||b||c||d; }
inline friend node operator + (const node A,const node B) { return node(A.a*B.a,A.b*B.a+B.b,A.a*B.c+A.c,A.b*B.c+A.d+B.d); }
}tmp;
struct seg { int l,r;LL val,sum;node flag;bool del; }tree[262144+10];
struct Query
{
int x,l,r,id,opt;
Query() {}
Query(int _x,int _l,int _r,int _id,int _opt) { x=_x;l=_l;r=_r;id=_id;opt=_opt; }
inline bool operator < (const Query& a)const { return x<a.x; }
}q[MAXN];
inline void add(int rt,node p)
{
int l=tree[rt].r-tree[rt].l+1;
tree[rt].sum+=p.c*tree[rt].val+p.d*l;
tree[rt].val=p.a*tree[rt].val+p.b*l;
tree[rt].flag=tree[rt].flag+p;
}
inline void push_down(int rt)
{
node t=tree[rt].flag;
if (tree[rt].del) tree[ln].val=tree[rn].val=tree[ln].sum=tree[rn].sum=0,tree[ln].flag=tree[rn].flag=node(),tree[ln].del=tree[rn].del=1,tree[rt].del=0;
if (t.a!=1||t.b||t.c||t.d) add(ln,t),add(rn,t),tree[rt].flag=node();
}
void build(int rt=1,int l=1,int r=n)
{
tree[rt].l=l;tree[rt].r=r;tree[rt].val=tree[rt].sum=0;tree[rt].flag=node();
if (l==r) return;
int mid=(l+r)>>1;build(lchild);build(rchild);
}
void modify(int rt,int l,int r)
{
int L=tree[rt].l,R=tree[rt].r,mid=(L+R)>>1;
if (l<=L&&r>=R) { add(rt,tmp);return; }
push_down(rt);
if (r<=mid) modify(ln,l,r);
else if (l>mid) modify(rn,l,r);
else modify(ln,l,mid),modify(rn,mid+1,r);
tree[rt].val=tree[ln].val+tree[rn].val;tree[rt].sum=tree[ln].sum+tree[rn].sum;
}
LL query(int rt,int l,int r)
{
int L=tree[rt].l,R=tree[rt].r,mid=(L+R)>>1;
if (l<=L&&r>=R) return tree[rt].sum;
push_down(rt);
if (r<=mid) return query(ln,l,r);
else if (l>mid) return query(rn,l,r);
else return query(ln,l,mid)+query(rn,mid+1,r);
tree[rt].val=tree[ln].val+tree[rn].val;tree[rt].sum=tree[ln].sum+tree[rn].sum;
}
int main()
{
in(n);in(m);int l,r;
for (int i=1;i<=n;i++) in(a[i]);
for (int i=1;i<=m;i++)
{
in(l);in(r);l1=l;r1=r;l2=1;r2=r;
if (l2>1) q[++cnt]=Query(l2-1,l1,r1,i,-1);
q[++cnt]=Query(r2,l1,r1,i,1);
}
sort(q+1,q+cnt+1);build();
for (int i=1,j=1;i<=n;sta[++top]=i++)
{
while (top&&a[sta[top]]>a[i]) top--;
tmp=node(0,a[i],0,0);modify(1,sta[top]+1,i);add(1,node(1,0,1,0));
while (j<=cnt&&q[j].x==i) ans[q[j].id]+=query(1,q[j].l,q[j].r)*q[j].opt,j++;
}
for (int i=1;i<=m;i++) printf("%lld\n",ans[i]);
}