bzoj 1938 - 类欧几里得+线段树

题目链接:https://darkbzoj.cf/problem/1938

 

解题思路;

对于区间更新:

前半部分可以用线段树求等差数列和,后半部分可以用类欧几里得算法求出值

类欧几里得

然后是要对区间离散化,其中有个问题在于对于区间(l,r)分裂为(l,mid)和(mid+1,r)都是mid-mid+1中还有值,

所以对于区间(l,r)实际包含的是(num[r+1]-num[l]),num[r+1]位置不算,所以在插入s[i].R时是加入s[i].R+1使得边界没有算入其中.

 

#include<math.h>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
using namespace std;
typedef __int128 ll;
const int mod = 1e9;
const int mx = 1e5 + 10;
int n,num[mx<<1],A,B,m,d; 
struct node
{
	int f;
	int L,R,A,B;
}s[mx];
ll sum[mx<<2];
int a[mx<<2],b[mx<<2],beg[mx<<2];
ll find(int x,int y,int z,ll len)
{
	if(!x) return (len+1)*(y/z);
	if(len<0) return 0;
	if(x>=z||y>=z){
		return find(x%z,y%z,z,len) + (x/z)*len*(len+1)/2 + (len+1)*(y/z);
	}
	ll up = (x*len+y)/z;
	return len*up - find(z,z-y-1,x,up-1);
}
void calc(int rt,int l,int r)
{
	ll N = (num[r+1]-num[l]);
	ll less = find(a[rt],0,b[rt],num[r+1]-1-beg[rt]) - find(a[rt],0,b[rt],num[l]-1-beg[rt]);
	less *= b[rt];
	sum[rt] = N*(num[l]-beg[rt])*a[rt]+(N*(N-1))/2*a[rt] - less;	
}
void push_up(int l,int r,int rt)
{
	int mid = (l+r)>>1;
	if(b[rt]){
		a[rt<<1] = a[rt<<1|1] = a[rt];
		b[rt<<1] = b[rt<<1|1] = b[rt];
		beg[rt<<1] = beg[rt<<1|1] = beg[rt];
		calc(rt<<1,l,mid);
		calc(rt<<1|1,mid+1,r);
		b[rt] = 0;
	}
}
void update(int l,int r,int rt,int L,int R)
{
	if(L<=l&&r<=R){
		a[rt] = A,b[rt] = B;
		beg[rt] = d;
		calc(rt,l,r);
		return ;
	}
	push_up(l,r,rt);
	int mid = (l+r)>>1;
	if(L<=mid) update(lson,L,R);
	if(R>mid) update(rson,L,R);
	sum[rt] = sum[rt<<1] + sum[rt<<1|1];
}
long long int query(int l,int r,int rt,int L,int R)
{
	if(L<=l&&r<=R) return sum[rt];
	push_up(l,r,rt);
	int mid = (l+r)>>1;
	long long int ans = 0;
	if(L<=mid) ans += query(lson,L,R);
	if(R>mid) ans += query(rson,L,R);
	return ans;
}
int main()
{
	int x,L,R;
	int top = 0;
	scanf("%d%d",&m,&n);
	for(int i=0;i<n;i++){
		scanf("%d",&s[i].f);
		scanf("%d%d",&s[i].L,&s[i].R);
		if(s[i].f==1) scanf("%d%d",&s[i].A,&s[i].B),s[i].A %= s[i].B;
		num[++top] = s[i].L;
		num[++top] = s[i].R+1;
	}
	sort(num+1,num+top+1);
	top = unique(num+1,num+top+1) - num;
	for(int i=0;i<n;i++){
		d = s[i].L - 1;
		int L = lower_bound(num+1,num+top,s[i].L) - num;
		int R = lower_bound(num+1,num+top,s[i].R+1) - num - 1;
		if(s[i].f==1){
			A = s[i].A,B = s[i].B;
			update(1,top-1,1,L,R);
		}else{
			printf("%lld\n",query(1,top-1,1,L,R));
		}
	}
	return 0;
} 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值