[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 } 
View Code

 

posted @ 2022-04-08 12:44  PYWBKTDA  阅读(284)  评论(0编辑  收藏  举报