[AGC025E]Walking on a Tree
题意:有一棵树,你要按顺序在树上走$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的更多相关文章
- K-D Tree
这篇随笔是对Wikipedia上k-d tree词条的摘录, 我认为解释得相当生动详细, 是一篇不可多得的好文. Overview A \(k\)-d tree (short for \(k\)-di ...
- 使控件具有 Tilt 效果
步骤1:添加类: /* Copyright (c) 2010 Microsoft Corporation. All rights reserved. Use of this sample source ...
- WinPhone学习笔记(四)——磁贴
对每个Windows Phone的使用者来说,给他们的第一印象就是大大小小的磁贴——Metro,本篇介绍的是Windows Phone的磁贴,提到的有开始菜单的磁贴,也有在App里面的磁贴. 开始菜单 ...
- java基础(1)-比较jdk5,jdk6,jdk7的新特性
jdk8已经出来好长时间了,这里自己学习时简单总结的jdk5,jdk6和jdk7的新特性:本文提纲: 一.jdk5的新特性 二.jdk6的新特性 三.jdk7的新特性 一.jdk5的新特性 首先简单介 ...
- 立即执行函数(IIFE)的理解与运用
作为JavaScript的常用语法,立即执行函数IIFE(Immediately-Invoked Function Expression)是值得我们认真去学习探究的. 一.创建函数的两种方式 我们先从 ...
- 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 ...
- (转载)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 ...
- Windows Phone 8 ControlTiltEffect
/* Copyright (c) 2010 Microsoft Corporation. All rights reserved. Use of this sample source code is ...
- jQuery的使用及关于框架造型(转)
Introduction 正如jQuery所宣称的一样,Write Less, Do More.很多时候我们喜欢用它来解决问题.但增加一个库必然意味着更大的网络负担,意味着更高的页面初始载入时间.并且 ...
随机推荐
- Android中使用RadioButton代替ImageButton
画外音————好久没上来发文章了,这几个月一直忙着一些跟编程不沾边的事,拖了好久,现在还在持续中,顺利的话7月份应该能解放了..今天偶尔上来写一段番外篇性质的心得发现. 之前搞的Android项目,作 ...
- poj 2104 (主席树写法)
//求第K的的值 1 #include<stdio.h> #include<iostream> #include<algorithm> #include<cs ...
- Input操作文件
在HTML表单中,可以上传文件的唯一控件就是<input type="file">. 注意:当一个表单包含<input type="file" ...
- 百度vue服务端渲染(ssr)有感
前端各种框架工具层次不穷,日新月异,越学越混乱了快 知乎上看到了一段回复,豁然开朗的感觉. Web 2.0时代最大的思想革命本质不是前后端分离,而是把网页当作独立的应用程序(app).前后端分离只是实 ...
- [洛谷P1032] 字串变换
洛谷题目链接:字串变换 题目描述 已知有两个字串 A, B 及一组字串变换的规则(至多6个规则): A1 -> B1 A2 -> B2 规则的含义为:在 A$中的子串 A1 可以变换为 B ...
- setInterval的使用和停用
var res = self.setInterval(function(){ if(typeof(UE.getEditor('editor').body.innerHTML) != "und ...
- web前端 html基础2
表单标签<form></form> input系列标签 text 文本输入框 placeholder 默认的属性,输入时消失 password 密码输入框 radio 单选框 ...
- linux服务与进程
linux服务与进程 http://www.cnblogs.com/jamesbd/p/3567654.html linux服务与进程 1.应用程序 2.服务脚本 3.配置文件 4.查看进程 5.查看 ...
- 自定义Java注解(annotation)
https://www.imooc.com/learn/456 笔记 Java从1.5开始引进注解. 首先解决一个问题,为什么要学习Java注解? 1.看懂别人写的代码,尤其是框架的代码 2.可以是 ...
- 1.kafka的介绍
kafka是一种高可用,高吞吐量,基于zookeeper协调的分布式发布订阅消息系统. 消息中间件:生产者和消费者 举个例子: 生产者:做馒头,消费者:吃馒头,数据流:馒头 如果消费者宕机了,吃不下去 ...