题意:有一棵树,你要按顺序在树上走$m$次,每次从$u_i$到$v_i$或从$v_i$到$u_i$,走完后,如果一条边被单向经过,那么它贡献$1$的价值,如果一条边被双向经过,那么它贡献$2$的价值,给出所有的$(u_i,v_i)$,你要安排每次走路的方向以最大化价值

设边$i$被经过的次数为$c_i$,容易看出答案的上界是$\sum\min(c_i,2)$,下面我们构造性地说明这个上界总可以被达到

如果$n=1$,树中没有边,接下来考虑$n\gt1$

任选一个叶子$u$,设$e$为连接它的唯一一边,$v$为$e$的另一端点

如果$c_e=0$,直接删掉$u$,这对答案没有影响

如果$c_e=1$,我们也可以删掉$u$,只不过经过$u$的那条路径的端点要缩至$v$,此时$e$贡献的价值为$1$

如果$c_e\geq2$,不停地选取两条路径$(u,a)$和$(u,b)$,那么我们可以把$(u,a)$和$(u,b)$换为$(a,b)$,如果$(a,b)$最终被决定为$a\rightarrow b$,那么还原过来就是$a\rightarrow u,u\rightarrow b$,否则是$b\rightarrow u,u\rightarrow a$,设$(u,c)$为$(u,a)$和$(u,b)$的交,那么$(u,c)$上的每一条边都一定能被双向经过,所以$e$贡献的价值为$2$,重复这个过程直至$c_e\lt2$,这样就构造性地说明了我们可以达到上界

我写得比较丑,毕竟是STL不用钱系列...

#include<stdio.h>
#include<string.h>
#include<vector>
using namespace std;
int h[2010],nex[4010],to[4010],dep[2010],fa[2010],fav[2010],M;
void add(int a,int b){
	M++;
	to[M]=b;
	nex[M]=h[a];
	h[a]=M;
}
void dfs(int x){
	dep[x]=dep[fa[x]]+1;
	for(int i=h[x];i;i=nex[i]){
		if(to[i]!=fa[x]){
			fa[to[i]]=x;
			dfs(to[i]);
		}
	}
}
void col(int x,int y){
	if(dep[x]<dep[y])swap(x,y);
	while(dep[x]>dep[y]){
		fav[x]++;
		x=fa[x];
	}
	while(x!=y){
		fav[x]++;
		fav[y]++;
		x=fa[x];
		y=fa[y];
	}
}
struct rt{
	int x,y;
	rt(int a=0,int b=0){x=a;y=b;}
};
bool operator==(rt a,rt b){return a.x==b.x&&a.y==b.y;}
int d[2010],n;
vector<rt>solve(vector<rt>v){
	if(v.size()==0)return v;
	int x,u,i;
	for(x=1;x<=n;x++){
		if(d[x]==1)break;
	}
	if(x>n)return v;
	for(i=h[x];i;i=nex[i]){
		if(d[to[i]]){
			u=to[i];
			break;
		}
	}
	d[x]--;
	d[u]--;
	vector<rt>lx,nv;
	vector<int>id;
	int pos[2010];
	memset(pos,-1,sizeof(pos));
	for(i=0;i<(int)v.size();i++){
		if(v[i].x==x||v[i].y==x){
			lx.push_back(v[i]);
			id.push_back(i);
		}else{
			nv.push_back(v[i]);
			pos[i]=nv.size()-1;
		}
	}
	if(lx.size()==0)return solve(v);
	for(i=0;i+1<(int)lx.size();i+=2){
		if(lx[i].y==x)swap(lx[i].x,lx[i].y);
		if(lx[i+1].y==x)swap(lx[i+1].x,lx[i+1].y);
		if(lx[i]==lx[i+1]){
			if(v[id[i]]==v[id[i+1]])swap(v[id[i]].x,v[id[i]].y);
			continue;
		}
		nv.push_back(rt(lx[i].y,lx[i+1].y));
		pos[id[i]]=pos[id[i+1]]=nv.size()-1;
	}
	if(lx.size()&1){
		if(lx[lx.size()-1].y==x)swap(lx[lx.size()-1].x,lx[lx.size()-1].y);
		if(lx[lx.size()-1].y!=u){
			nv.push_back(rt(u,lx[lx.size()-1].y));
			pos[id[lx.size()-1]]=nv.size()-1;
		}
	}
	nv=solve(nv);
	for(i=0;i<(int)v.size();i++){
		if(pos[i]!=-1&&!(v[i].x==nv[pos[i]].x||v[i].y==nv[pos[i]].y))swap(v[i].x,v[i].y);
	}
	return v;
}
vector<rt>v;
int main(){
	int m,i,x,y,ans;
	scanf("%d%d",&n,&m);
	for(i=1;i<n;i++){
		scanf("%d%d",&x,&y);
		add(x,y);
		add(y,x);
		d[x]++;
		d[y]++;
	}
	dfs(1);
	for(i=1;i<=m;i++){
		scanf("%d%d",&x,&y);
		v.push_back(rt(x,y));
		col(x,y);
	}
	v=solve(v);
	ans=0;
	for(i=2;i<=n;i++)ans+=min(2,fav[i]);
	printf("%d\n",ans);
	for(rt t:v)printf("%d %d\n",t.x,t.y);
}

[AGC025E]Walking on a Tree的更多相关文章

  1. K-D Tree

    这篇随笔是对Wikipedia上k-d tree词条的摘录, 我认为解释得相当生动详细, 是一篇不可多得的好文. Overview A \(k\)-d tree (short for \(k\)-di ...

  2. 使控件具有 Tilt 效果

    步骤1:添加类: /* Copyright (c) 2010 Microsoft Corporation. All rights reserved. Use of this sample source ...

  3. WinPhone学习笔记(四)——磁贴

    对每个Windows Phone的使用者来说,给他们的第一印象就是大大小小的磁贴——Metro,本篇介绍的是Windows Phone的磁贴,提到的有开始菜单的磁贴,也有在App里面的磁贴. 开始菜单 ...

  4. java基础(1)-比较jdk5,jdk6,jdk7的新特性

    jdk8已经出来好长时间了,这里自己学习时简单总结的jdk5,jdk6和jdk7的新特性:本文提纲: 一.jdk5的新特性 二.jdk6的新特性 三.jdk7的新特性 一.jdk5的新特性 首先简单介 ...

  5. 立即执行函数(IIFE)的理解与运用

    作为JavaScript的常用语法,立即执行函数IIFE(Immediately-Invoked Function Expression)是值得我们认真去学习探究的. 一.创建函数的两种方式 我们先从 ...

  6. An NIO.2 primer--reference

    Part 1: The asynchronous channel APIs The More New I/O APIs for the Java™ Platform (NIO.2) is one of ...

  7. (转载)XML Tutorial for iOS: How To Choose The Best XML Parser for Your iPhone Project

    There are a lot of options when it comes to parsing XML on the iPhone. The iPhone SDK comes with two ...

  8. Windows Phone 8 ControlTiltEffect

    /* Copyright (c) 2010 Microsoft Corporation. All rights reserved. Use of this sample source code is ...

  9. jQuery的使用及关于框架造型(转)

    Introduction 正如jQuery所宣称的一样,Write Less, Do More.很多时候我们喜欢用它来解决问题.但增加一个库必然意味着更大的网络负担,意味着更高的页面初始载入时间.并且 ...

随机推荐

  1. [BZOJ3594] [Scoi2014]方伯伯的玉米田 二维树状数组优化dp

    我们发现任何最优解都可以是所有拔高的右端点是n,然后如果我们确定了一段序列前缀的结尾和在此之前用过的拔高我们就可以直接取最大值了然后我们在这上面转移就可以了,然后最优解用二维树状数组维护就行了 #in ...

  2. jQuery源码分析笔记

    jquery-2.0.3.js版本源码分析 (function(){  (21,94) 定义了一些变量和函数 jQuery = function(){};  (96,283) 给JQ对象,添加一些方法 ...

  3. 如何用listview显示服务端数据

    https://www.cnblogs.com/caobotao/p/5061627.html

  4. ACM模板~求第k短路 ~~~A*+Dijkstra

    #include <map> #include <set> #include <cmath> #include <ctime> #include < ...

  5. fastjson对json操作

    fastjson对json字符串JSONObject和JSONArray互相转换操作示例  fastjson的方法: Fastjson API入口类是com.alibaba.fastjson.JSON ...

  6. org.apache.hadoop.hdfs.server.datanode.DataNode: Exception in receiveBlock for block

    Hbase依赖的datanode日志中如果出现如下报错信息:DataXceiverjava.io.EOFException: INFO org.apache.hadoop.hdfs.server.da ...

  7. js中Date()对象详解

    var myDate = new Date(); myDate.getYear(); //获取当前年份(2位) myDate.getFullYear(); //获取完整的年份(4位,1970-???? ...

  8. 【洛谷 P1437】 [HNOI2004]敲砖块 (DP)

    题目链接 毒瘤DP题 因为\((i,j)\)能不能敲取决于\((i-1,j)\)和\((i-1,j+1)\),所以一行一行地转移显然是有后效性的. 于是考虑从列入手.我们把这个三角形"左对齐 ...

  9. bzoj 2005 NOI 2010 能量采集

    我们发现对于一个点(x,y),与(0,0)连线上的点数是gcd(x,y)-1 那么这个点的答案就是2*gcd(x,y)-1,那么最后的答案就是所有点 的gcd值*2-n*m,那么问题转化成了求每个点的 ...

  10. Kali Linux中前十名的Wifi攻击工具

    无 线网络的攻与防一直是比较热门的话题,由于无线信号可以被一定范围内的任何人接收到(包括死黑阔),这样就给WIFI带来了安全隐患:路由器生产厂商和网 络服务供应商(ISPs)的配置大多是默认开启了WP ...