4262: Sum
Time Limit: 20 Sec Memory Limit: 256 MBSubmit: 77 Solved: 38
[ Submit][ Status][ Discuss]
Description

Input
第一行一个数 t,表示询问组数。
第一行一个数 t,表示询问组数。
接下来 t 行,每行四个数 l_1, r_1, l_2, r_2。
Output
一共 t 行,每行一个数 Sum。
Sample Input
4
1 3 5 7
2 4 6 8
1 1 9 9
9 9 1 1
1 3 5 7
2 4 6 8
1 1 9 9
9 9 1 1
Sample Output
9322587654
9025304064
1065645568
0
9025304064
1065645568
0
HINT
1<=t<=40000,1<=L1<R1<=10^5,1<=L2<=R2<=10^5
Source
题解:线段树
与bzoj 4540的线段树做法是基本相同的。对于每组询问我们拆成两部分(l,r,l2-1)(l,r,r2),用后一部分的答案-前一部分的答案。
调试的时候发现一个昨天没有注意到的问题,就是在更新sum,val的时候一定是先更新sum,再更新val。为什么呢?写出转移的矩阵就会发现,更新sum的val其实是未更新前的val。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define LL long long
#define N 100003
#define p 1000000000
using namespace std;
int n,m,cnt,top,top1,st[N],st1[N];
LL ans[N],a[N];
struct node{
LL a,b,c,d;
void clear() {a=1,b=c=d=0;}
};
node operator +(node x,node y){
return (node){x.a*y.a,y.b+x.b*y.a,x.a*y.c+x.c,x.d+y.d+x.b*y.c};
}
struct data{
LL sum[N*4],val[N*4];
node delta[N*4];
void update(int now){
sum[now]=sum[now<<1]+sum[now<<1|1];
val[now]=val[now<<1]+val[now<<1|1];
}
void add(int now,int l,int r,node t){
LL len=(LL)(r-l+1);
sum[now]+=val[now]*t.c+t.d*len;
val[now]=t.a*val[now]+t.b*len;
delta[now]=delta[now]+t;
}
void pushdown(int now,int l,int r) {
node t=delta[now];
int mid=(l+r)/2;
if (t.a!=1||t.b||t.c||t.d) {
add(now<<1,l,mid,t); add(now<<1|1,mid+1,r,t);
delta[now].clear();
}
}
void build(int now,int l,int r) {
val[now]=sum[now]=0; delta[now].clear();
if (l==r) return;
int mid=(l+r)/2;
build(now<<1,l,mid); build(now<<1|1,mid+1,r);
update(now);
}
void qjchange(int now,int l,int r,int ll,int rr,node t){
if (ll<=l&&r<=rr) {
add(now,l,r,t);
return;
}
int mid=(l+r)/2;
pushdown(now,l,r);
if (ll<=mid) qjchange(now<<1,l,mid,ll,rr,t);
if (rr>mid) qjchange(now<<1|1,mid+1,r,ll,rr,t);
update(now);
}
LL qjsum(int now,int l,int r,int ll,int rr) {
if (ll<=l&&r<=rr) return sum[now];
int mid=(l+r)/2; LL ans=0;
pushdown(now,l,r);
if (ll<=mid) ans+=qjsum(now<<1,l,mid,ll,rr);
if (rr>mid) ans+=qjsum(now<<1|1,mid+1,r,ll,rr);
return ans;
}
}mx,mn;
void get_a(int n)
{
LL x=1,y=1;
for (int i=1;i<=n;i++) {
x=x*1023%p; y=y*1025%p;
a[i]=x^y;
}
}
struct hp{
int l,r,id,opt,end;
}q[N];
int cmp(hp a,hp b){
return a.end<b.end;
}
int main()
{
freopen("a.in","r",stdin);
scanf("%d",&m);
for (int i=1;i<=m;i++) {
int l1,l2,r1,r2; scanf("%d%d%d%d",&l1,&r1,&l2,&r2);
if (l1>r2) continue;
if (l2>1) q[++cnt].l=l1,q[cnt].r=r1,q[cnt].end=l2-1,q[cnt].id=i,q[cnt].opt=-1;
q[++cnt].l=l1; q[cnt].r=r1; q[cnt].end=r2; q[cnt].id=i; q[cnt].opt=1;
n=max(n,r2);
}
get_a(n);
sort(q+1,q+cnt+1,cmp);
top=0; top1=0; int j=1;
mx.build(1,1,n); mn.build(1,1,n);
for (int i=1;i<=n;i++) {
while (top&&a[st[top]]>=a[i]) top--;
node tmp=(node){0,a[i],0,0}; mn.qjchange(1,1,n,st[top]+1,i,tmp);
tmp=(node){1,0,1,0}; st[++top]=i;
mn.add(1,1,n,tmp);
while (top1&&a[st1[top1]]<=a[i]) top1--;
tmp=(node){0,a[i],0,0}; mx.qjchange(1,1,n,st1[top1]+1,i,tmp);
tmp=(node){1,0,1,0}; st1[++top1]=i;
mx.add(1,1,n,tmp);
while (j<=cnt&&q[j].end==i)
ans[q[j].id]+=(LL)q[j].opt*(mx.qjsum(1,1,n,q[j].l,q[j].r)-mn.qjsum(1,1,n,q[j].l,q[j].r)),j++;
}
for (int i=1;i<=m;i++) printf("%I64d\n",ans[i]);
}