bzoj2138(hall定理+线段树)

题目链接

https://www.lydsy.com/JudgeOnline/problem.php?id=2138

题解

感觉还是比较经典的。。

对前 $i-1$ 个区间排序,然后选定他们的子集来和 $i$ 并,

若该子集的并区间不连续,那么把他们分割后必然是更严格的条件,所以这个检验是冗余的。。

然后如果连续,那么被该并区间包含的区间是必选的,不选的话只会使得条件更加宽松。。

那么思路就有了,对前 $i-1$ 个区间进行排序,然后直接确定连续的区间作为 hall 定理的判定子集,即选定 $i,j$ ,使

然后分离变量之后会发现只需要维护最值就可以了,直接线段树做

由于插入 $i$ 时前 $i-1$ 个已经满足条件,所以我们选定的连续子集必须包含 $i$ ,所以这个最值可以在 $i$ 的两侧直接取得。。




代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
/*
*         ┏┓    ┏┓
*         ┏┛┗━━━━━━━┛┗━━━┓
*         ┃       ┃  
*         ┃   ━    ┃
*         ┃ >   < ┃
*         ┃       ┃
*         ┃... ⌒ ...  ┃
*         ┃ ┃
*         ┗━┓ ┏━┛
*          ┃ ┃ Code is far away from bug with the animal protecting          
*          ┃ ┃ 神兽保佑,代码无bug
*          ┃ ┃           
*          ┃ ┃       
*          ┃ ┃
*          ┃ ┃           
*          ┃ ┗━━━┓
*          ┃ ┣┓
*          ┃ ┏┛
*          ┗┓┓┏━━━━━━━━┳┓┏┛
*           ┃┫┫ ┃┫┫
*           ┗┻┛ ┗┻┛
*/

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
#include<map>
#include<stack>
#include<cmath>
#include<set>
#include<bitset>
#include<assert.h>
#define inc(i,l,r) for(int i=l;i<=r;i++)
#define dec(i,l,r) for(int i=l;i>=r;i--)
#define link(x) for(edge *j=h[x];j;j=j->next)
#define mem(a) memset(a,0,sizeof(a))
#define ll long long
#define eps 1e-8
#define succ(x) (1<<x)
#define lowbit(x) (x&(-x))
#define sqr(x) ((x)*(x))
#define mid (x+y>>1)
#define NM 40005
#define nm 200005
#define pi 3.1415926535897931
#define mp(x,y) make_pair(x,y)
using namespace std;
const int inf=1e9;
ll read(){
ll x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
return f*x;
}



struct P{int l,r;}c[NM];
int n,m,_x,_y,_z,_t,p;
int a[NM],b[NM],id[NM],tmp[NM];
bool cmp(int x,int y){return c[x].l<c[y].l||(c[x].l==c[y].l&&c[x].r<c[y].r);}
struct node{
int x,y,tag,_tag,s,_s;
node*l,*r;
node(int x,int y,node*l=0,node*r=0):x(x),y(y),l(l),r(r),tag(0),_tag(0){if(l)upd(),_upd();else s=a[c[tmp[x]].r],_s=a[c[tmp[x]].l-1];}
void upd(){s=min(l->s,r->s);}
void _upd(){_s=max(l->_s,r->_s);}
void push(){
if(tag){
l->s+=tag;l->tag+=tag;
r->s+=tag;r->tag+=tag;
tag=0;
}
if(_tag){
l->_s+=_tag;l->_tag+=_tag;
r->_s+=_tag;r->_tag+=_tag;
_tag=0;
}
}
void mod(){
if(_x<=x){tag-=_t;s-=_t;return;}
push();if(_x<=mid)l->mod();r->mod();upd();
}
void ch(){
if(_x<=x){_tag-=_t;_s-=_t;return;}
push();if(_x<=mid)l->ch();r->ch();_upd();
}
int smin(){
if(y<_x)return inf;
if(_x<=x)return s;
push();return min(l->smin(),r->smin());
}
int smax(){
if(_x<x)return -inf;
if(y<=_x)return _s;
push();return max(l->smax(),r->smax());
}
}*root;
node*build(int x,int y){return x==y?new node(x,y):new node(x,y,build(x,mid),build(mid+1,y));}



int main(){
n=read();
_x=read();_y=read();_z=read();p=read();
inc(i,1,n)a[i]=(sqr(i-_x)%p+sqr(i-_y)%p+sqr(i-_z)%p)%p+a[i-1];
m=read();if(m==0)return 0;
b[1]=read();b[2]=read();_x=read();_y=read();_z=read();p=read();
inc(i,3,m)b[i]=(_x*b[i-1]+_y*b[i-2]+_z)%p;
inc(i,1,m)c[i].l=read(),c[i].r=read(),tmp[i]=i;
sort(tmp+1,tmp+1+m,cmp);
inc(i,1,m)id[tmp[i]]=i;
root=build(1,m);
//inc(i,1,n)printf("%d ",a[i]-a[i-1]);putchar('\n');
//inc(i,1,m)printf("%d ",b[i]);putchar('\n');
//inc(i,1,m)printf("%d %d\n",c[i].l,c[i].r);putchar('\n');
inc(i,1,m){
_x=id[i];
_t=b[i]=min(b[i],root->smin()-root->smax());
printf("%d\n",b[i]);
root->mod();_x++;if(_x<=m)root->ch();
}
return 0;
}