1. 程式人生 > >bzoj 1938 - 類歐幾里得+線段樹

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