传送门:QAQQAQ题面翻译

以后博客可能一直咕咕咕了。一些做题的思考可能会直接放在代码里而不是单独写博客,因为这样太浪费时间,只有一些比较新的题才会单独写博客

思路:对于这种构造可行解使得权值和恰好为某一值的题,一般都是先求出可以构造出来的最大和最小值,然后从某个极值按照一定方法进行连续修改

我们考虑每一条边对于答案的贡献:若边$E(u,v)$把数分成$U,V$两颗子树,则该边最大的贡献是$min(sz[U],sz[V])$,最小是$sz[U]\mod2$。

$min$太难处理,所以想一种办法把$min$去掉,通过重心的性质(每一个子树的$size$小于等于$\frac{n}{2}$),发现直接取重心就可以把$min$去掉了

所以就可以得到

$$minans=\sum_{i=1}^{n} [i \neq root]sz[i]\mod2$$

$$maxans=\sum_{i=1}^{n} [i \neq root]sz[i]$$

然后仔细想想会发现:答案有解的充要条件是$minans \leq k \leq maxans$且$(maxans-k)\mod2=0$

充分性:通过构造方法证明。

  每次取在$size$最大的子树中选取两个$lca$深度最大的点,因为本来两个点都是向字树外连的,现在自己相连,所以$\Delta =2*dep[lca]$,然后删掉那两个点

  容易发现这样构造是必定可以从$maxans$变成$minans$的,因为对于$sz[u]\mod2=0$的边,它底下肯定两两配对;对于$sz[u]\mod2=0$,这样的贪心会使得下面只有一个点向上经过它

  因为点数始终为偶数,所以从最大子树删掉两个点以后不会使得次大子树的$size$大于$\frac{n}{2}$,上面求$minans,maxans$的式子始终成立

  当最后一次$dep[lca]*2>rest$时,因为所有不是叶子节点的点都可以作$lca$,所以$dep$必定连续,即肯定能找到构造出刚好使得$rest=0$的方案。

  剩下的点按照$max$的方案,跨子树分别连就可以了

必要性:因为$\Delta =2*dep[lca]$,所以如果不是$k,maxans$不是同奇同偶,一定无解

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=120000;
typedef long long ll;
typedef pair<int,int> pii;
#define mk make_pair
int n; ll k; vector<int> v[N];
int sz[N],dep[N],fa[N],root; ll minn=N,maxn=0;
void dfs1(int u,int f)
{
sz[u]=1; int maxsz=0;
for(int i=0;i<(int)v[u].size();i++)
{
int to=v[u][i]; if(to==f) continue;
dfs1(to,u); sz[u]+=sz[to];
maxsz=max(maxsz,sz[to]);
}
if(minn>max(maxsz,n-sz[u])) minn=max(maxsz,n-sz[u]),root=u;
} int top[N],deg[N];
set<pii> S[N],R;//S维护子树中所有可能作为lca的点(即不是叶子)
void dfs(int u,int from)
{
sz[u]=1;
top[u]=from;
if(from&&(int)v[u].size()-1>=1) S[from].insert(mk(dep[u],u));
for(int i=0;i<(int)v[u].size();i++)
{
int to=v[u][i]; if(to==fa[u]) continue;
if(u==root) from=to; deg[u]++;
dep[to]=dep[u]+1; fa[to]=u;
dfs(to,from); sz[u]+=sz[to];
}
} void del(int x)
{
if(!--deg[fa[x]])
S[top[x]].erase(mk(dep[fa[x]],fa[x]));
} int vis[N];
vector<int> rem;
void dfs3(int u)
{
if(!vis[u]) rem.push_back(u);
for(int i=0;i<(int)v[u].size();i++)
{
int to=v[u][i]; if(to==fa[u]) continue;
dfs3(to);
}
} int main()
{
scanf("%d%lld",&n,&k);
for(int i=1;i<n;i++)
{
int x,y; scanf("%d%d",&x,&y);
v[x].push_back(y); v[y].push_back(x);
}
dfs1(1,-1); dep[root]=0; dfs(root,0);
minn=0,maxn=0;
for(int i=1;i<=n;i++)
if(i!=root) maxn+=sz[i], minn+=sz[i]%2;
if(k>maxn||k<minn||(maxn-k)&1) {puts("NO"); return 0;}
puts("YES");
for(int i=0;i<v[root].size();i++)
{
int to=v[root][i];
if(sz[to]>1) R.insert(mk(sz[to],to));
}
ll rest=maxn-k;
while(rest)
{
int now=R.rbegin()->second; R.erase(--R.end());
int pos=S[now].rbegin()->second;
if(2*dep[pos]>rest)
{
rest/=2;
pos=S[now].lower_bound(mk(rest,0))->second;
vector<int> V; V.clear();
for(int i=0;i<(int)v[pos].size();i++)
{
int to=v[pos][i];
if(to==fa[pos]||vis[to]) continue;
V.push_back(to);
}
if((int)V.size()<2) V.push_back(pos);
printf("%d %d\n",V[0],V[1]); vis[V[0]]=1; vis[V[1]]=1;
rest-=dep[pos];
break;
}
else
{
vector<int> V; V.clear();
for(int i=0;i<(int)v[pos].size();i++)
{
int to=v[pos][i];
if(to==fa[pos]||vis[to]) continue;
V.push_back(to);
}
if((int)V.size()<2) V.push_back(pos); rest-=dep[pos]*2;
printf("%d %d\n",V[0],V[1]); vis[V[0]]=1; vis[V[1]]=1;
del(V[0]); del(V[1]);
}
sz[now]-=2;
if(sz[now]>1) R.insert(mk(sz[now],now));
}
dfs3(root);
int T=(int)rem.size()/2;
for(int i=0;i<T;i++) printf("%d %d\n",rem[i],rem[i+T]);
return 0;
}

CF1396E——Distance Matching的更多相关文章

  1. [cf1396E]Distance Matching

    根据$dis(x,y)=d[x]+d[y]-2d[lca(x,y)]$,由于所有点都出现了1次,距离即$\sum_{i=1}^{n}d_{i}-2\sum d[lca(x,y)]$(以下假设根深度为0 ...

  2. [atARC087F]Squirrel Migration

    对这棵树重心情况分类讨论: 1.若这棵树存在两个重心,分别记作$x$和$y$,如果将$(x,y)$断开,两棵子树大小都相同(都为$\frac{n}{2}$),此时$p_{i}$与$i$必然不同属于一个 ...

  3. world.construct(me);

    目录 0 引言 0.1 所谓构造题 0.2 重点是动机 (motivation) 1 实践出真知 1.1 「CSP-S 2021」「洛谷 P7915」回文 1.1.1 题目大意 1.1.2 解题过程 ...

  4. 最喜欢的算法(们) - Levenshtein distance

    String Matching: Levenshtein distance Purpose: to use as little effort to convert one string into th ...

  5. Scipy教程 - 距离计算库scipy.spatial.distance

    http://blog.csdn.net/pipisorry/article/details/48814183 在scipy.spatial中最重要的模块应该就是距离计算模块distance了. fr ...

  6. Direct Shot Correspondence Matching

    一篇BMVC18的论文,关于semantic keypoints matching.dense matching的工作,感觉比纯patch matching有意思,记录一下. 1. 摘要 提出一种针对 ...

  7. Matching Networks for One Shot Learning

    1. Introduction In this work, inspired by metric learning based on deep neural features and memory a ...

  8. Hausdorff Distance(豪斯多夫距离)

    Hausdorff Distance(豪斯多夫距离) 参考博客:http://cgm.cs.mcgill.ca/~godfried/teaching/cg-projects/98/normand/ma ...

  9. Minimum edit distance(levenshtein distance)(最小编辑距离)初探

    最小编辑距离的定义:编辑距离(Edit Distance),又称Levenshtein距离.是指两个字串之间,由一个转成还有一个所需的最少编辑操作次数.许可的编辑操作包含将一个字符替换成还有一个字符. ...

随机推荐

  1. 制作u盘启动盘

    制作u盘启动盘 如果是想要制作 windows 系统启动盘,windows 官网提供途径,这里不在赘述. 以下讨论制作 centos 系统启动盘,需要 centos 系统文件,开源,可从官网下载得到. ...

  2. spring-boot-route(八)整合mybatis操作数据库

    MyBatis 是一款优秀的持久层框架,它支持定制化 SQL.存储过程以及高级映射.MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集.MyBatis 可以使用简单的 XML ...

  3. Matlab绘制子图subplot使用攻略

    参考:https://jingyan.baidu.com/article/915fc414ad794b51394b20e1.html Matlab绘制子图subplot使用攻略 听语音 原创 | 浏览 ...

  4. 【题解】[USACO19DEC]Milk Visits G

    题目戳我 \(\text{Solution:}\) 这题不要把思想局限到线段树上--这题大意就是求路径经过的值中\(x\)的出现性问题. 最开始的想法是值域线段树--看了题解发现直接\(vector\ ...

  5. Hello World背后的事情

    Hello World是不少人学习C++的第一项内容,代码看似简单,很多东西却涉及根本 #include <iostream> using namespace std; int main( ...

  6. MeteoInfo 新网站

    MeteoInfo特别是MeteoInfoLab的推广需要写大量详细的帮助文档和示例程序,MeteoInfo原先的网站使用最原始的编写.html文件的方式来更新,效率实在太低,最近学习了一下Sphin ...

  7. day28 Pyhton MRO和C3算法

    1.python多继承.一个类可以拥有多个父类 class ShenXian: # 神仙 def fei(self): print("神仙都会飞") class Monkey: # ...

  8. 还不会ida*算法?看完这篇或许能理解点。

    IDA* 算法分析 IDA* 本质上就是带有估价函数和迭代加深优化的dfs与,A * 相似A *的本质便是带 有估价函数的bfs,估价函数是什么呢?估价函数顾名思义,就是估计由目前状态达 到目标状态的 ...

  9. 【动态规划】DP搬运工3

    UPD:修了点锅(啊昨天居然写脑抽了) 题目内容 给定两个长度为 \(n\) 的序列,定义 \(magic(A,B)=\sum\limits_{i=1}^n \max(A_i,B_i)\). 现在给定 ...

  10. harbor搭建与使用

        前两天测试服务docker化并k8s布署时,出于方便,使用了docker hub.由于我们的代码是要放到镜像里的,通过运行容器,便能获取我们的全部代码,风险很大.所以我们决定进行私有化的镜像部 ...