【题解】bzoj 2138: stone hall定理+线段树

题目
题解

**
选出的点必须存在完备匹配。于是用hall定理转化问题
考虑每个区间都符合hall定理则肯定有解
因为区间不包含可以用TR[R] - TL[L - 1]表示在【L,R】的询问区间
每次询问是前缀max 和 后缀min之差 , 因为所有区间都满足hall定理才行
具体看yyb的题解、。我就不赘述了
**

注意:前缀max包含0位置,所以最小值为0

#include<bits/stdc++.h>
using namespace std;

#define rep(i,l,r) for(register int i = l ; i <= r ; i++)
#define repd(i,r,l) for(register int i = r ; i >= l ; i--)
#define rvc(i,S) for(register int i = 0 ; i < (int)S.size() ; i++)
#define rvcd(i,S) for(register int i = ((int)S.size()) - 1 ; i >= 0 ; i--)
#define fore(i,x)for (register int i = head[x] ; i ; i = e[i].next)
#define forup(i,l,r) for (register int i = l ; i <= r ; i += lowbit(i))
#define fordown(i,id) for (register int i = id ; i ; i -= lowbit(i))
#define pb push_back
#define prev prev_
#define stack stack_
#define mp make_pair
#define fi first
#define se second
#define lowbit(x) (x&(-x))

typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef unsigned int ui;
typedef pair<int,int> pr;

const int inf = 1e9;
const int maxn = 100020;

int mod;
int sum[maxn],x,y,z,P,a[maxn],n,m,K[maxn];

namespace Seg{
#define ls(x) (x << 1)
#define rs(x) ((x << 1) | 1)
	const int M = 4e4 + 20;
	int mn[M << 2],addmn[M << 2],mx[M << 2],addmx[M << 2];
	
	
	inline void update(int x){
		mn[x] = min(mn[ls(x)],mn[rs(x)]);
		mx[x] = max(mx[ls(x)],mx[rs(x)]);
	}
	void build(int x,int l,int r){
		if ( l == r ){
			mx[x] = mn[x] = sum[l];  
			return;
		}
		int mid = (l + r) >> 1;
		build(ls(x),l,mid) , build(rs(x),mid + 1,r);
		update(x);
	}
	inline void addmn_(int x,int d){
		addmn[x] += d;
		mn[x] += d;
	}
	inline void addmx_(int x,int d){
		addmx[x] += d;
		mx[x] += d;
	}
	inline void pushdown(int x){
		if ( addmn[x] ){
			addmn_(ls(x),addmn[x]);
			addmn_(rs(x),addmn[x]);
			addmn[x] = 0;
		}
		if ( addmx[x] ){
			addmx_(ls(x),addmx[x]);
			addmx_(rs(x),addmx[x]);
			addmx[x] = 0;
		}
	}
	/*
	void modify(int x,int l,int r,int id,ui d){
		if ( l == r ){
			mul[x] = d;
			return;
		}
		int mid = (l + r) >> 1;
		if ( id <= mid ) modify(ls(x),l,mid,id,d);
		else modify(rs(x),mid + 1,r,id,d);
		update(x);
	}*/
	void modifymn(int x,int l,int r,int L,int R,int d){
		if ( L > R ) return;
		if ( L <= l && R >= r ){ addmn_(x,d); return; }
		pushdown(x);
		int mid = (l + r) >> 1;
		if ( L <= mid ) modifymn(ls(x),l,mid,L,R,d);
		if ( R > mid ) modifymn(rs(x),mid + 1,r,L,R,d);
		update(x);
	}
	
	void modifymx(int x,int l,int r,int L,int R,int d){
		if ( L > R ) return;
		if ( L <= l && R >= r ){ addmx_(x,d); return; }
		pushdown(x);
		int mid = (l + r) >> 1;
		if ( L <= mid ) modifymx(ls(x),l,mid,L,R,d);
		if ( R > mid ) modifymx(rs(x),mid + 1,r,L,R,d);
		update(x);
	}
	int querymn(int x,int l,int r,int L,int R){
		if ( L > R ) return 0;
		if ( L <= l && R >= r ) return mn[x];
		pushdown(x);
		int mid = (l + r) >> 1; int res = inf;
		if ( L <= mid ) res = querymn(ls(x),l,mid,L,R);
		if ( R > mid ) res = min(res,querymn(rs(x),mid + 1,r,L,R));
		return res;
	}
	int querymx(int x,int l,int r,int L,int R){
		if ( L > R ) return 0;
		if ( L <= l && R >= r ) return mx[x];
		pushdown(x);
		int mid = (l + r) >> 1; int res = 0;//从0开始,为了方便,把初始设为0
		if ( L <= mid ) res = querymx(ls(x),l,mid,L,R);
		if ( R > mid ) res = max(res,querymx(rs(x),mid + 1,r,L,R));
		return res;
	}
}
using namespace Seg;


int main(){
//	freopen("input.txt","r",stdin);
	scanf("%d",&n);
	scanf("%d %d %d %d",&x,&y,&z,&P);
	rep(i,1,n){
		a[i] = ((ll)(i - x) * (i - x) + (i - y) * (i - y) + (i - z) * (i - z)) % P;
		sum[i] = sum[i - 1] + a[i];
//		cout<<a[i]<<" ";
	}
//	cout<<endl;
	build(1,1,n);
	scanf("%d %d %d",&m,&K[1],&K[2]);
	scanf("%d %d %d %d",&x,&y,&z,&P);
	rep(i,3,m){
		K[i] = ((ll)x * K[i - 1] + y * K[i - 2] + z) % P;
	
	}
//	rep(i,1,m) 	cout<<K[i]<<" ";
//	cout<<endl;
	rep(i,1,m){
		
		int l,r;
		scanf("%d %d",&l,&r);
		int mnf = querymn(1,1,n,r,n);
		int mxg = querymx(1,1,n,1,l - 1);
	//	cout<<mnf<<" "<<mxg<<endl;
		int delta = min(K[i],mnf - max(0,mxg));
		printf("%d\n",delta);
		modifymn(1,1,n,r,n,-delta);
		modifymx(1,1,n,l,n,-delta);
	}
}

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值