• [luogu7417]Minimizing Edges P


    令$e_{G}(a)$和$o_{G}(a)$分别表示在图$G$中从1到$a$的长度为奇数/偶数的最短路(若该类最短路不存在则为$infty$),不难得到有以下结论——$f_{G}(a,b)=egin{cases}[bge e_{G}(a)]&(bequiv 0(mod 2))\ [bge o_{G}(a)]&(bequiv 1(mod 2))end{cases}$

    根据这个结论,即要求$forall a,e_{G}(a)=e_{G'}(a)$且$o_{G}(a)=o_{G'}(a)$

    先对原图$G$求出所有$e_{G}(a)$和$o_{G}(a)$,将$a$拆为$a_{0}$和$a_{1}$,并对边$(a,b)$连$(a_{0},b_{1})$和$(a_{1},b_{0})$,最后从$1_{0}$出发bfs即可,时间复杂度为$o(n)$

    记$G'$的边集为$E$,那么$forall a,e_{G}(a)=e_{G'}(a)$且$o_{G}(a)=o_{G'}(a)$当且仅当满足以下两个条件:

    1.$(a,b)in E,|e_{G}(a)-o_{G}(b)|=1$且$|e_{G}(b)-o_{G}(a)|=1$(特别的,定义$|infty-infty|=1$)

    2.$forall e_{G}(a) e 0,infty,exists (a,b)in E,e_{G}(a)=o_{G}(b)+1$且$forall o_{G}(a) e infty,exists (a,b)in E,o_{G}(a)=e_{G}(b)+1$

    (关于这个结论,必要性显然,充分性拆点后对距离从小到大归纳即可)

    若存在$a$满足$e_{G}(a)=infty$,那么根据第1个条件,与其相连的点$o_{G}(b)=infty$,以此类推,所有点(原图连通)$b$都满足$e_{G}(b)=infty$或$o_{G}(b)=infty$($o_{G}(a)=infty$同理)

    此时,对于第2个条件,除1以外(1没有限制)每一个点仅有1维有限制,只需要连向一个可以使其该维满足第2个条件的点,显然这样的点必然存在,最终的边数即为$n-1$

    (也即原图没有奇环,不能调整奇偶性,构造方案即取以1为根的最短路径树)

    考虑这种情况后,即$forall a,e_{G}(a),o_{G}(a) e infty$,将其作为点$(min(e_{G}(a),o_{G}(a)),max(e_{G}(a),o_{G}(a)))$,并将所有点$(x,y)$按照$x+y$从小到大排序、$x+y$相同时$x$从小到大排序

    现在,我们从前往后,依次考虑当前点$(x,y)$,去连边满足其第2个条件

    如果之前存在点$(x-1,y+1)$“未完全合法”,显然从中任选一个连边即可,连边后$(x,y)$也成为一个“未完全合法”的点(还需要与$(xpm 1,y-1)$连边),暂不处理

    否则,如果之前存在点$(x-1,y-1)$,直接连边即可,即满足条件

    否则,再找到$(x-1,y+1)$连边(若$x=0$时不需要连,否则必然存在),并作为“未完全合法”的点

    另外,若$y=x+1$且$(x,y)$作为“未完全合法”的点,注意到$(x+1,y-1)$实际上是$(x,y)$自己,因此若之间存在点$(x,y)$“未完全合法”,将这两点连边即可(并取消两点“未完全合法”的标记)

    最终,对于剩下的“未完全合法”的点$(x,y)$,找到$(xpm 1,y-1)$连边即可,由于必然存在,即边数加上“未完全合法”的点数量即可

    (当然这个数量也可以在修改过程中顺便加上)

    由此,用map维护$(x,y)$上“未完全合法”的点数量即可支持此过程,时间复杂度为$o(nlog n)$

    (关于这一做法的正确性,即是一个贪心,比较显然)

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define N 200005
     4 struct Edge{
     5     int nex,to;
     6 }edge[N<<2];
     7 queue<int>q;
     8 vector<pair<int,int> >v;
     9 map<int,int>mat_vis[N],mat[N];
    10 int E,t,n,m,x,y,ans,head[N],vis[N],d[N]; 
    11 void add(int x,int y){
    12     edge[E].nex=head[x];
    13     edge[E].to=y;
    14     head[x]=E++;
    15 }
    16 void bfs(){
    17     d[1]=0;
    18     q.push(1);
    19     vis[1]=1;
    20     while (!q.empty()){
    21         int k=q.front();
    22         q.pop();
    23         for(int i=head[k];i!=-1;i=edge[i].nex)
    24             if (!vis[edge[i].to]){
    25                 d[edge[i].to]=d[k]+1;
    26                 q.push(edge[i].to);
    27                 vis[edge[i].to]=1;
    28             }
    29     }
    30 }
    31 int main(){
    32     scanf("%d",&t);
    33     while (t--){
    34         scanf("%d%d",&n,&m);
    35         E=ans=0;
    36         for(int i=0;i<=(n<<1);i++){
    37             head[i]=d[i]=-1;
    38             vis[i]=0;
    39             mat_vis[i].clear(),mat[i].clear();
    40         }
    41         for(int i=1;i<=m;i++){
    42             scanf("%d%d",&x,&y);
    43             add(x,y+n);
    44             add(y+n,x);
    45             add(x+n,y);
    46             add(y,x+n);
    47         } 
    48         bfs();
    49         if (d[n+1]<0){
    50             printf("%d
    ",n-1);
    51             continue;
    52         }
    53         v.clear();
    54         for(int i=1;i<=n;i++)v.push_back(make_pair(min(d[i],d[i+n]),max(d[i],d[i+n])));
    55         sort(v.begin(),v.end());
    56         for(int i=0;i<n;i++)mat_vis[v[i].first][v[i].second]=1;
    57         for(int i=0;i<n;i++){
    58             x=v[i].first,y=v[i].second;
    59             if ((x)&&(mat[x-1][y+1])){
    60                 mat[x-1][y+1]--;
    61                 mat[x][y]++;
    62                 ans++;
    63             }
    64             else{
    65                 if ((x)&&(mat_vis[x-1][y-1]))ans++;
    66                 else{
    67                     mat[x][y]++;
    68                     ans+=1+(x>0);
    69                 }
    70             }
    71             if ((y==x+1)&&(mat[x][y]>=2)){
    72                 mat[x][y]-=2;
    73                 ans--;
    74             }
    75         }
    76         printf("%d
    ",ans);
    77     }
    78 }
    View Code
  • 相关阅读:
    python的类基础
    python导入模块
    python常用的内置函数
    python基础一数据类型之集合
    python函数-匿名函数
    python的函数(三)
    python的函数(二)
    python的函数(一)
    BZOJ4104:[Thu Summer Camp 2015]解密运算——题解
    BZOJ4033:[HAOI2015]树上染色——题解
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/14871101.html
Copyright © 2020-2023  润新知