• [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
  • 相关阅读:
    Linux操作系统原理
    html标签简介(常用)
    Git常用命名
    Nuxt.js vue服务端渲染
    Sequelize 和 MySQL 对照Sequelize 和 MySQL 对照
    VScode 自定义用户代码块
    python对一个文本的解析
    API管理工具
    Flutter教程- Dart语言规范-知识点整理
    RESTful API
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/16116347.html
Copyright © 2020-2023  润新知