zoukankan      html  css  js  c++  java
  • CodeForces 589H Tourist Guide

    传送门

    题目大意

    给定$n$个点$m$条边的无向图,有$K$个关键点,你要尽可能的让这些关键点两两匹配,使得所有点对之间可以通过简单路径连接且任意两个简单路径没有重复的边(可以是共同经过一个点),输出每一条这样的路径。

    $Kleq n,mleq 5 imes 10^4$

    题解

    很显然对于每一个连通块,当且仅当它有奇数个关键点,那么它会有一个关键点没有被配对,否则一定可以满足两两配对。

    考虑该联通块的任意一棵生成树,不考虑是否经过了同一条边,任意两两沿着树上简单路径染边。

    若有$(a,b)cap (c,d) = (p,q)$其中$(x,y)$表示从$x,y$之间的简单路径(设$a,c$在$p$的同侧)。

    那么只需要令$a,c$配对,$c,d$配对即可。

    至于方案数,任意选择一棵生成树进行搜索即可,$G_x$表示以$x$为根的子树内没有配对的点是多少(若没有则$G_x=0$)。

    枚举$x$的每个儿子$v$,若$G_v=0$就忽略,否则,若$G_x=0$,那么令$G_x=G_v$,不然就新建一条以$x$为$lca$的,一端是$G_x$一端是$G_v$的路径,再让$G_x=0$即可。

    复杂度$O(n)$。

    #include<bits/stdc++.h>
    #define LL long long
    #define M 100020
    using namespace std;
    namespace IO{
    	const int BS=(1<<20)+5; int Top=0;
    	char Buffer[BS],OT[BS],*OS=OT,*HD,*TL,SS[20]; const char *fin=OT+BS-1;
    	char Getchar(){if(HD==TL){TL=(HD=Buffer)+fread(Buffer,1,BS,stdin);} return (HD==TL)?EOF:*HD++;}
    	void flush(){fwrite(OT,1,OS-OT,stdout);}
    	void Putchar(char c){*OS++ =c;if(OS==fin)flush(),OS=OT;}
    	void write(int x){
    		if(!x){Putchar('0');return;} if(x<0) x=-x,Putchar('-');
    		while(x) SS[++Top]=x%10,x/=10;
    		while(Top) Putchar(SS[Top]+'0'),--Top;
    	}
    	int read(){
    		int nm=0,fh=1; char cw=Getchar();
    		for(;!isdigit(cw);cw=Getchar()) if(cw=='-') fh=-fh;
    		for(;isdigit(cw);cw=Getchar()) nm=nm*10+(cw-'0');
    		return nm*fh;
    	}
    }
    using namespace IO;
    int n,K,m,fs[M],to[M],G[M],nt[M],fa[M],u[M],v[M],t[M],tot,tmp;
    int s1[M],s2[M]; bool vs[M];
    #define link(a,b) nt[tmp]=fs[a],fs[a]=tmp,to[tmp++]=b
    #define ins(a,b,c) tot++,u[tot]=a,v[tot]=b,t[tot]=c
    void dp(int x){
    	G[x]=vs[x]?x:0;
    	for(int i=fs[x];i!=-1;i=nt[i]){
    		if(fa[to[i]]) continue;
    		fa[to[i]]=x,dp(to[i]);
    		if(!G[to[i]]) continue;
    		if(!G[x]) G[x]=G[to[i]];
    		else ins(G[x],G[to[i]],x),G[x]=0;
    	}
    }
    void opt(int x,int y,int k){
    	int tp1=0,tp2=0;
    	while(x!=k) s1[++tp1]=x,x=fa[x];
    	while(y!=k) s2[++tp2]=y,y=fa[y];
    	write(tp1+tp2),Putchar(' ');
    	for(int i=1;i<=tp1;i++) write(s1[i]),Putchar(' '); write(k);
    	for(int i=tp2;i>=1;i--) Putchar(' '),write(s2[i]); Putchar('
    ');
    }
    int main(){
    	n=read(),m=read(),K=read(),memset(fs,-1,sizeof(fs));
    	for(int i=1;i<=m;i++){int x=read(),y=read();link(x,y),link(y,x);}
    	for(int i=1;i<=K;i++) vs[read()]=true;
    	for(int i=1;i<=n;i++) if(!fa[i]) fa[i]=i,dp(i);
    	write(tot),Putchar('
    ');
    	for(int i=1;i<=tot;i++) opt(u[i],v[i],t[i]);
    	flush(); return 0;
    }
    

      

  • 相关阅读:
    村上春树的《海边的卡夫卡》与中日现实
    熊的甜蜜世界
    VS创建dll和调用dll
    DIRECTSHOW在VS2005中PVOID64问题和配置问题
    Vs 2008 解决方案的目录结构设置和管理
    SQL Server 2008中的代码安全(二):DDL触发器与登录触发器
    如何在自动SGA管理模式下调节参数设置
    将ORACLE数据库从归档改成非归档状态
    查看oracle数据库是否归档和修改归档模式(转)
    oracle TRANSLATE函数详解
  • 原文地址:https://www.cnblogs.com/OYJason/p/9877283.html
Copyright © 2011-2022 走看看