bzoj 4262: Sum (线段树)

4262: Sum

Time Limit: 20 Sec   Memory Limit: 256 MB
Submit: 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

Sample Output

9322587654
9025304064
1065645568
0

HINT

1<=t<=40000,1<=L1<R1<=10^5,1<=L2<=R2<=10^5


Source

[ Submit][ Status][ Discuss]

题解:线段树

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]);
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值