假设把每堆石子拆成 Ai A i 个点,每个询问拆成 Ki K i 个点,就相当于每次添加 Ki K i 个点,然后询问此时的最大匹配能增加多少。
通过Hall定理可以判断匹配的合法性。但因为本题的区间没有包含,把询问按照 Li L i 排序, Ri R i 是递增的,在剔除掉没有被任一区间覆盖的石子堆之后,一段询问区间对应的石子也是一段连续的区间,我们不需要判断每个子集,而只需要判断每个区间是否满足Hall定理即可。
设 Bi B i 是排序后第 i i 个询问所选的石子个数,那么只要满足对于任意 l≤r l ≤ r ,有
代码:
#include
#include
#include
#include
#define N 40010
#define ll long long
#define mid (l+r>>1)
using namespace std;
int n,m,a[N],o[N];
struct node
{
int l,r,k,t,id;
}b[N];
bool cmpl(node p,node q)
{
return p.l<q.l;
}
bool cmpt(node p,node q)
{
return p.t<q.t;
}
int read()
{
int x=0,f=1;char ch=getchar();
for(;ch<'0'||ch>'9';ch=getchar()) if(ch=='-') f=-1;
for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
return x*f;
}
struct tree
{
int s[N<<2],add[N<<2];
bool flag;
int M(int x,int y)
{
return flag?max(x,y):min(x,y);
}
void update(int v)
{
s[v]=M(s[v<<1],s[v<<1|1]);
}
void cal(int v,int d)
{
s[v]+=d;add[v]+=d;
}
void pushdown(int v)
{
if(add[v])
{
cal(v<<1,add[v]);
cal(v<<1|1,add[v]);
add[v]=0;
}
}
void build(int v,int l,int r)
{
if(l==r) {s[v]=flag?-a[b[r].r]:-a[b[l].l-1];return ;}
build(v<<1,l,mid);
build(v<<1|1,mid+1,r);
update(v);
}
void mdf(int v,int l,int r,int lx,int rx,int c)
{
if(l==lx&&r==rx) {cal(v,c);return ;}
pushdown(v);
if(rx<=mid) mdf(v<<1,l,mid,lx,rx,c);
else if(lx>mid) mdf(v<<1|1,mid+1,r,lx,rx,c);
else mdf(v<<1,l,mid,lx,mid,c),mdf(v<<1|1,mid+1,r,mid+1,rx,c);
update(v);
}
int qry(int v,int l,int r,int lx,int rx)
{
if(l==lx&&r==rx) return s[v];
pushdown(v);
if(rx<=mid) return qry(v<<1,l,mid,lx,rx);
if(lx>mid) return qry(v<<1|1,mid+1,r,lx,rx);
return M(qry(v<<1,l,mid,lx,mid),qry(v<<1|1,mid+1,r,mid+1,rx));
}
}Tl,Tr;
int main()
{
n=read();
int x=read(),y=read(),z=read(),p=read();
for(int i=1;i<=n;i++)
a[i]=((ll)(i-x)*(i-x)+(i-y)*(i-y)+(i-z)*(i-z))%p;
m=read();
if(!m) return 0;
b[1].k=read();b[2].k=read();x=read();y=read();z=read();p=read();
for(int i=3;i<=m;i++)
b[i].k=((ll)x*b[i-1].k+y*b[i-2].k+z)%p;
for(int i=1;i<=m;i++)
b[i].l=read(),b[i].r=read(),b[i].t=i;
sort(b+1,b+m+1,cmpl);
for(int i=1;i<=m;i++)
b[i].id=i;
b[m+1].l=n+1;
for(int i=1;i<=m+1;i++)
{
int tmp=b[i].l-b[i-1].r-1;
if(tmp>0) o[b[i].l]+=tmp;
}
for(int i=1;i<=n;i++)
o[i]+=o[i-1];
for(int i=1;i<=n;i++)
a[i-o[i]]=a[i];
for(int i=1;i<=m;i++)
b[i].l-=o[b[i].l],b[i].r-=o[b[i].r];
n-=o[n];
for(int i=1;i<=n;i++)
a[i]+=a[i-1];
Tl.flag=0;Tr.flag=1;
Tl.build(1,1,m);
Tr.build(1,1,m);
sort(b+1,b+m+1,cmpt);
for(int i=1;i<=m;i++)
{
int ans=min(Tl.qry(1,1,m,1,b[i].id)-Tr.qry(1,1,m,b[i].id,m),b[i].k);
printf("%d\n",ans);
if(b[i].id<m) Tl.mdf(1,1,m,b[i].id+1,m,ans);
Tr.mdf(1,1,m,b[i].id,m,ans);
}
return 0;
}