BZOJ2138 : stone
根据Hall定理,若存在一个区间满足内部需求数$>$内部石子数,则不存在完美匹配。
由于区间互不包含,所以设:
$a[i]$表示右端点$\leq i$的区间的容量之和。
$b[i]$表示左端点$\leq i$的区间的容量之和。
$s[i]$表示前$i$个位置的石子数之和。
则区间$[l,r]$的:
石子数$=s[r]-s[l-1]$。
需求数$=a[r]-b[l-1]$。
即对于任意$0\leq i<j\leq n$,要满足:
$\min((s[j]-a[j])-(s[i]-b[i]))\geq 0$
设
$f[i]=s[i]-a[i]$
$g[i]=s[i]-b[i]$
考虑$[l,r]$区间需求数为$k$时对匹配的影响:
$f[r..n]-=k$
$g[l..n]-=k$
那么当$k$取$\min(f[\geq r])-\max(g[<l])$时刚好满足所有限制。
线段树维护即可。
时间复杂度$O(m\log n)$。
#include<cstdio> #include<algorithm> using namespace std; const int N=40010,M=131100,inf=~0U>>1; int n,m,i,x,y,z,P,a[N],f[M],g[M],tf[M],tg[M]; inline void tagf(int x,int y){f[x]+=y;tf[x]+=y;} inline void tagg(int x,int y){g[x]+=y;tg[x]+=y;} inline void pb(int x){ if(tf[x])tagf(x<<1,tf[x]),tagf(x<<1|1,tf[x]),tf[x]=0; if(tg[x])tagg(x<<1,tg[x]),tagg(x<<1|1,tg[x]),tg[x]=0; } inline void up(int x){ f[x]=min(f[x<<1],f[x<<1|1]); g[x]=max(g[x<<1],g[x<<1|1]); } void build(int x,int a,int b){ if(a==b){f[x]=g[x]=::a[a];return;} int mid=(a+b)>>1; build(x<<1,a,mid),build(x<<1|1,mid+1,b); up(x); } void changef(int x,int a,int b,int c,int d,int p){ if(c<=a&&b<=d){tagf(x,-p);return;} pb(x); int mid=(a+b)>>1; if(c<=mid)changef(x<<1,a,mid,c,d,p); if(d>mid)changef(x<<1|1,mid+1,b,c,d,p); up(x); } void changeg(int x,int a,int b,int c,int d,int p){ if(c<=a&&b<=d){tagg(x,-p);return;} pb(x); int mid=(a+b)>>1; if(c<=mid)changeg(x<<1,a,mid,c,d,p); if(d>mid)changeg(x<<1|1,mid+1,b,c,d,p); up(x); } int askf(int x,int a,int b,int c,int d){ if(c<=a&&b<=d)return f[x]; pb(x); int mid=(a+b)>>1,t=inf; if(c<=mid)t=askf(x<<1,a,mid,c,d); if(d>mid)t=min(t,askf(x<<1|1,mid+1,b,c,d)); return t; } int askg(int x,int a,int b,int c,int d){ if(c<=a&&b<=d)return g[x]; pb(x); int mid=(a+b)>>1,t=-inf; if(c<=mid)t=askg(x<<1,a,mid,c,d); if(d>mid)t=max(t,askg(x<<1|1,mid+1,b,c,d)); return t; } int main(){ scanf("%d%d%d%d%d",&n,&x,&y,&z,&P); for(i=1;i<=n;i++)a[i]=(1LL*(i-x)*(i-x)+1LL*(i-y)*(i-y)+1LL*(i-z)*(i-z))%P,a[i]+=a[i-1]; build(1,0,n); scanf("%d%d%d%d%d%d%d",&m,&a[1],&a[2],&x,&y,&z,&P); for(i=3;i<=m;i++)a[i]=(1LL*x*a[i-1]+1LL*y*a[i-2]+z)%P; for(i=1;i<=m;i++){ scanf("%d%d",&x,&y); printf("%d\n",z=min(askf(1,0,n,y,n)-askg(1,0,n,0,x-1),a[i])); changef(1,0,n,y,n,z); changeg(1,0,n,x,n,z); } return 0; }