bzoj 4262: Sum

来源:互联网 发布:页面性能优化 编辑:程序博客网 时间:2024/06/04 00:48
把询问离线下来,查询max和查询min相似,现在只考虑查询max
令sum[l,r,x]表示l到r内的数为左端点,x为右端点的区间询问的答案
那么询问就是sun[l1,r1,r2]-sum[l1,r1,l1-1]
从1到n枚举x,维护区间线段树表示sum[l,r,x],发现从x-1转移到x的过程中,每个数加上了max(a[pos]..a[x])的答案。
用单调队列维护一个单调递减的序列,由于a数列是随机的,这个队列期望有log个元素,所以只需要对这log段暴力修改,复杂度nlog^2n
或者,只在元素进队和出队的时候做一些操作,写起来会复杂很多,但复杂度nlogn
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
 
#define unl unsigned long long
#define inf 1e9
#define eps 1e-8
#define md 1000000000
#define N 100010
using namespace std;
struct QQ { int l,r,x,ty,id;} q[N];
struct Tr { int l,r; unl sz,ad,sum;} tr[4*N];
int a[N],st[N];
unl jia[N],jian[N];
int n;
 
void get()
{
unl mi1=1,mi2=1;
for (int i=1;i<=n;i++)
{
mi1=mi1*1023%md; mi2=mi2*1025%md;
a[i]=mi1^mi2;
}
}
 
bool cmp(QQ a,QQ b) { return a.x<b.x;}
 
void addit(int i,unl d)
{
tr[i].ad+=d;
tr[i].sum+=d*tr[i].sz;
}
 
void release(int i)
{
if (tr[i].ad!=0)
{
unl d=tr[i].ad; tr[i].ad=0;
addit(i<<1,d); addit(i<<1|1,d);
}
}
 
void build(int i,int l,int r)
{
tr[i].l=l; tr[i].r=r; tr[i].sz=r-l+1; tr[i].ad=tr[i].sum=0;
if (l==r) return;
int mid=(l+r)>>1;
build(i<<1,l,mid); build(i<<1|1,mid+1,r);
}
 
void add(int i,int ql,int qr,unl d)
{
if (ql<=tr[i].l&&tr[i].r<=qr)
{
addit(i,d);
return;
}
release(i);
int mid=(tr[i].l+tr[i].r)>>1;
if (ql<=mid) add(i<<1,ql,qr,d);
if (mid+1<=qr) add(i<<1|1,ql,qr,d);
tr[i].sum=tr[i<<1].sum+tr[i<<1|1].sum;
}
 
unl query(int i,int ql,int qr)
{
if (ql<=tr[i].l&&tr[i].r<=qr) return tr[i].sum;
release(i);
int mid=(tr[i].l+tr[i].r)>>1;
if (qr<=mid) return query(i<<1,ql,qr);
if (mid+1<=ql) return query(i<<1|1,ql,qr);
return query(i<<1,ql,qr)+query(i<<1|1,ql,qr);
}
 
int main()
{
int m;
scanf("%d",&m);
int cnt=0;
for (int i=1;i<=m;i++)
{
int l1,r1,l2,r2;
scanf("%d%d%d%d",&l1,&r1,&l2,&r2);
q[++cnt]=(QQ){l1,r1,l2-1,0,i}; q[++cnt]=(QQ){l1,r1,r2,1,i};
n=max(n,max(r1,r2));
}
get();
sort(q+1,q+cnt+1,cmp);
build(1,1,n);
int top=0,now=0;
while (now<cnt&&q[now+1].x==0) now++;
for (int i=1;i<=n;i++)
{
while (top&&a[st[top]]<=a[i]) top--;
st[++top]=i;
for (int j=1;j<=top;j++) add(1,st[j-1]+1,st[j],a[st[j]]);
while (now<cnt&&q[now+1].x==i)
{
now++; unl sum=query(1,q[now].l,q[now].r);
if (q[now].ty) jia[q[now].id]+=sum; else jian[q[now].id]+=sum;
}
}
build(1,1,n);
top=0; now=0;
while (now<cnt&&q[now+1].x==0) now++;
for (int i=1;i<=n;i++)
{
while (top&&a[st[top]]>=a[i]) top--;
st[++top]=i;
for (int j=1;j<=top;j++) add(1,st[j-1]+1,st[j],a[st[j]]);
while (now<cnt&&q[now+1].x==i)
{
now++; unl sum=query(1,q[now].l,q[now].r);
if (q[now].ty) jian[q[now].id]+=sum; else jia[q[now].id]+=sum;
}
}
for (int i=1;i<=m;i++) printf("%llu\n",jia[i]-jian[i]);
printf("\n");
return 0;
}

0 0