[loj3693]蚂蚁与方糖
对于二分图$G=(V_{l}\cup V_{r},E)$,记$N(S)=\{y\mid \exists x\in S,(x,y)\in E\}$
结论:$G$的最大匹配$=\min_{S\subseteq V_{l}}(|V_{l}|-|S|+|N(S)|)$
将$V_{l}-S$和$N(S)$中的点全部删除,显然剩下的$S$和$V_{r}-N(S)$中不存在边
删除的点至多产生$|V_{l}|-|S|+|N(S)|$组匹配,因此最大匹配$\le |V_{l}|-|S|+|N(S)|$
另一方面,考虑取到最小值的$S$,证明可以达到该上界——
若删除的点内部匹配显然无法达到上界,因此仅能在另一边的补集内匹配
换言之,达到上界等价于$N(S)$在$S$内、$V_{l}-S$在$V_{r}-N(S)$内存在完美匹配
结合hall定理,并使用反证法,具体如下:
假设存在$T\subseteq N(S)$使得$|N(T)\cap S|<|T|$,取$S'=S-N(T)$,注意到$N(S')\cap T=\empty$,则
$$
|N(S')|-|S'|\le (|N(S)|-|T|)-(|S|-|N(T)\cap S|)<|N(S)|-|S|
$$
假设存在$T\subseteq V_{l}-S$使得$|N(T)\cap V_{r}-N(S)|<|T|$,取$S'=S\cup T$,则
$$
|N(S')|-|S'|=(|N(S)|+|N(T)\cap V_{r}-N(S)|)-(|S|+|T|)<|N(S)|-|S|
$$
两种情况均与$S$取到最小值矛盾,即得证
回到原问题,即求将相距$\le L$的蚂蚁和方糖连边后的最大匹配(对每个蚂蚁/方糖建点)
根据上述结论,考虑取到最小值的$S$,并分析其性质——
性质1:同一个位置上的蚂蚁总是全选/全不选
部分选与全选时$N(S)$不变且$S$变小,显然不优
将蚂蚁的位置(从左到右)依次编号为$1,2,...,m$,记$x_{i}$为坐标$,s_{i}$为蚂蚁数
根据性质1,$S$可以用$[1,m]$的子集描述,且对应的值即$\sum_{i=1}^{m}s_{i}-\sum_{i\in S}s_{i}+|\bigcup_{i\in S}N(i)|$
性质2:记$nex_{i}(S)$为$S$中$i$的后继,则$|\bigcup_{i\in S}N(i)|=\sum_{i\in S}|N(i)|-|N(i)\cap N(nex_{S}(i))|$
引理:$\forall x\in V_{r}$,满足$x\in N(i)$的$i$构成连续区间(或为空)
结合引理,每一个$x\in \bigcup_{i\in S}N(i)$恰会在该区间与$S$交的最后一项中贡献,即得证
性质3:若$l,r\in S$且$x_{r}-x_{l}\le 2L$,则$\forall i\in [l,r],i\in S$
引理:若$x_{r}-x_{l}\le 2L$,则$\forall i\in [l,r],N(i)\subseteq N(l)\cup N(r)$
结合引理,$\forall i\in [l,r],P_{i}=0$与$P_{i}=1$时$N(S)$不变且$S$变小,显然不优
结合性质2和性质3,即$N(i)\cap N(nex_{S}(i))\ne \empty$(可推出$x_{nex_{S}(i)}-x_{i}\le 2L$)时$i+1\in S$,进而$nex_{S}(i)=i+1$
综上,问题即求
$$
\sum_{i=1}^{m}s_{i}+\min_{S\subseteq [1,m]}\left(\sum_{i\in S}(|N(i)|-s_{i})-\sum_{i,i+1\in S}|N(i)\cap N(i+1)|\right)
$$
线段树维护$|N(mid)\cap N(mid+1)|$和区间内左右端点是否选择时的答案,即可实现push-up
加入蚂蚁即单点修改,加入方糖即区间修改,并分析修改的形式:
假设$[x_{l},x_{r}]\subseteq [x-L,x+L]$且最长,则修改即$\begin{cases}\forall i\in [l,r],|N(i)|+x\\\forall i\in [l,r),|N(i)\cap N(i+1)|+x\end{cases}$
进一步的,对于一种选法的影响即$+kx$(其中$k$为选择的极长区间数)
注意到$x_{r}-x_{l}\le 2L$,结合性质3即$k\in \{0,1\}$,并特判不选(即$k=0$)的情况即可
时间复杂度为$o(n\log n)$,可以通过
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 500005 4 #define ll long long 5 #define L (k<<1) 6 #define R (L+1) 7 #define mid (l+r>>1) 8 int n,m,l,p[N],x[N],y[N],v[N]; 9 ll sum,tag[N<<2],val[N<<2]; 10 struct Data{ 11 ll a[4]; 12 ll get(){ 13 return min(min(a[0],a[1]),min(a[2],a[3])); 14 } 15 }f[N<<2]; 16 void upd(int k,ll x){ 17 tag[k]+=x,val[k]+=x; 18 for(int i=0;i<4;i++)f[k].a[i]+=x; 19 f[k].a[0]=min(f[k].a[0],0LL); 20 } 21 void up(int k){ 22 for(int i=0;i<4;i++)f[k].a[i]=1e18; 23 for(int i=0;i<4;i++) 24 for(int j=0;j<4;j++){ 25 int s=(i&2|j&1),p=(i&(j>>1)&1); 26 f[k].a[s]=min(f[k].a[s],f[L].a[i]+f[R].a[j]-p*val[k]); 27 } 28 } 29 void down(int k){ 30 if (tag[k])upd(L,tag[k]),upd(R,tag[k]),tag[k]=0; 31 } 32 void build(int k,int l,int r){ 33 if (l==r){ 34 f[k].a[1]=f[k].a[2]=1e18; 35 return; 36 } 37 build(L,l,mid),build(R,mid+1,r); 38 up(k); 39 } 40 void update(int k,int l,int r,int x,int y){ 41 if (l==r){ 42 f[k].a[3]+=y; 43 return; 44 } 45 down(k); 46 if (x<=mid)update(L,l,mid,x,y); 47 else update(R,mid+1,r,x,y); 48 up(k); 49 } 50 void update(int k,int l,int r,int x,int y,int z){ 51 if ((l>y)||(x>r))return; 52 if ((x<=l)&&(r<=y)){ 53 upd(k,z); 54 return; 55 } 56 down(k); 57 update(L,l,mid,x,y,z),update(R,mid+1,r,x,y,z); 58 if ((x<=mid)&&(mid<y))val[k]+=z; 59 up(k); 60 } 61 int main(){ 62 scanf("%d%d",&n,&l); 63 for(int i=1;i<=n;i++){ 64 scanf("%d%d%d",&p[i],&x[i],&y[i]); 65 if (p[i]==1)v[++m]=x[i]; 66 } 67 if (!m){ 68 for(int i=1;i<=n;i++)printf("0\n"); 69 return 0; 70 } 71 sort(v+1,v+m+1),build(1,1,m); 72 for(int i=1;i<=n;i++){ 73 if (p[i]==1){ 74 int pos=lower_bound(v+1,v+m+1,x[i])-v; 75 sum+=y[i],update(1,1,m,pos,-y[i]); 76 } 77 if (p[i]==2){ 78 int posl=lower_bound(v+1,v+m+1,x[i]-l)-v; 79 int posr=upper_bound(v+1,v+m+1,x[i]+l)-v-1; 80 update(1,1,m,posl,posr,y[i]); 81 } 82 printf("%lld\n",sum+f[1].get()); 83 } 84 return 0; 85 }