题解

贪心+线段树

首先如果我们知道了哪些点是关键点应该怎么搞

显然最小的匹配方案所有的边至多被经过一次

可以考虑每条边的贡献

因为我们要贡献尽量小

所以我们尽量让每条边经过的人尽量少

那么每条边被经过的条件就是一条边连接的两个节点的子树内关键点数量是奇数

然后我们可以直接考虑每条边会被多少个区间影响

一条边能被一个区间影响的条件就是这个区间的大小是偶数且这个区间内在这个边的深度较深的端点的子树内的点的数量有奇数个

也就是满足\(j-i=0(\mod 2) s_j - s_i=1(\mod 2)\)

这个东西可以用线段树维护

就记录下标为\(奇数/偶数\)且前缀和为奇数的数量

那么修改就是修改从这个点到\(m\)都翻转,并且可以直接计算了

然后可以用线段树合并来处理这个东西

但是我写了半天写不动><

就直接上dsu on tree来搞子树了==

代码

#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
# define ls (now << 1)
# define rs (now << 1 | 1)
const int M = 100005 ;
const int N = 20 ;
const int mod = 998244353 ;
using namespace std ;
inline int read() {
char c = getchar() ; int x = 0 , w = 1 ;
while(c>'9'||c<'0') { if(c=='-') w = -1 ; c = getchar() ; }
while(c>='0'&&c<='9') { x = x*10+c-'0' ; c = getchar() ; }
return x*w ;
} int n , m ;
int num , hea[M] ;
int cnt , ans , fdis[M] ;
int size[M] , bsn[M] ;
vector < int > vec[M] ;
struct E {
int nxt , to , dis ;
} edge[M * 2] ;
struct Node {
bool rev ;
int odd , even ;
} t[M * N] ;
inline void add_edge(int from , int to , int dis) {
edge[++num].nxt = hea[from] ;
edge[num].to = to ;
edge[num].dis = dis ;
hea[from] = num ;
}
inline void Flip(int now , int l , int r) {
t[now].even = r / 2 - (l - 1) / 2 - t[now].even ;
t[now].odd = (r + 1) / 2 - l / 2 - t[now].odd ;
t[now].rev ^= 1 ;
}
inline void pushup(int now) {
t[now].odd = t[ls].odd + t[rs].odd ;
t[now].even = t[ls].even + t[rs].even ;
}
inline void pushdown(int now , int l , int r) {
if(t[now].rev) {
t[now].rev = 0 ; int mid = (l + r) >> 1 ;
if(ls) Flip(ls , l , mid) ; if(rs) Flip(rs , mid + 1 , r) ;
}
}
void Change(int L , int R , int l , int r , int now) {
if(!now || l > R || r < L) return ;
if(l >= L && r <= R) { Flip(now , l , r) ; return ; }
pushdown(now , l , r) ;
int mid = (l + r) >> 1 ;
if(mid >= R) Change(L , R , l , mid , ls) ;
else if(mid < L) Change(L , R , mid + 1 , r , rs) ;
else { Change(L , mid , l , mid , ls) ; Change(mid + 1 , R , mid + 1 , r , rs) ; }
pushup(now) ;
}
inline void Calc(int u) {
int sum_e = m / 2 + 1 , sum_o = (m + 1) / 2 ;
ans = ((ans + 1LL * fdis[u] * t[1].even % mod * (sum_e - t[1].even) % mod) % mod + 1LL * fdis[u] * t[1].odd % mod * (sum_o - t[1].odd) % mod) % mod ;
}
void fdfs(int u , int father) {
size[u] = 1 ; int mx = -1 ;
for(int i = hea[u] ; i ; i = edge[i].nxt) {
int v = edge[i].to ; if(v == father) continue ;
fdis[v] = edge[i].dis ;
fdfs(v , u) ; size[u] += size[v] ;
if(size[v] > mx) mx = size[v] , bsn[u] = v ;
}
} inline void Add(int u) {
for(int i = 0 , x , sz = vec[u].size() ; i < sz ; i ++) {
x = vec[u][i] ;
Change(x , m , 1 , m , 1) ;
}
}
void Update(int u , int father) {
Add(u) ;
for(int i = hea[u] ; i ; i = edge[i].nxt) {
int v = edge[i].to ;
if(v != father)
Update(v , u) ;
}
}
void dfs(int u , int father , bool Kp) {
for(int i = hea[u] ; i ; i = edge[i].nxt) {
int v = edge[i].to ;
if(v != father && v != bsn[u])
dfs(v , u , 0) ;
}
if(bsn[u]) dfs(bsn[u] , u , 1) ;
for(int i = hea[u] ; i ; i = edge[i].nxt) {
int v = edge[i].to ;
if(v != father && v != bsn[u])
Update(v , u) ;
}
Add(u) ;
if(fdis[u]) {
int sum_e = m / 2 + 1 , sum_o = (m + 1) / 2 ;
ans = (ans + 1LL * fdis[u] * t[1].even % mod * (sum_e - t[1].even) % mod) % mod ;
ans = (ans + 1LL * fdis[u] * t[1].odd % mod * (sum_o - t[1].odd) % mod) % mod ;
}
if(!Kp) Update(u , father) ;
}
int main() {
n = read() ; m = read() ;
for(int i = 1 , u , v , w ; i < n ; i ++) {
u = read() ; v = read() ; w = read() ;
add_edge(u , v , w) ; add_edge(v , u , w) ;
}
for(int i = 1 , x ; i <= m ; i ++) {
x = read() ;
vec[x].push_back(i) ;
}
fdfs(1 , 0) ;
dfs(1 , 0 , 1) ;
printf("%d\n",ans) ;
return 0 ;
}

[UOJ388]配对树的更多相关文章

  1. 【UOJ#388】【UNR#3】配对树(线段树,dsu on tree)

    [UOJ#388][UNR#3]配对树(线段树,dsu on tree) 题面 UOJ 题解 考虑一个固定区间怎么计算答案,把这些点搞下来建树,然后\(dp\),不难发现一个点如果子树内能够匹配的话就 ...

  2. 【UOJ388】配对树(dsu on tree+线段树)

    传送门 题意: 给出一颗含有\(n\)个结点的无根树,之后给出一个长度为\(m\)的序列,每个元素在\([1,n]\)之间. 现在序列中每个长度为偶数的区间的完成时间定义为树上最小配对方法中每对匹配点 ...

  3. [UOJ388]【UNR #3】配对树

    uoj description 给你一棵\(n\)个节点的树以及一个长为\(m\)的序列,序列每个位置上的值\(\in[1,n]\),你需要求出把序列中所有长度为偶数的区间内所有数拿出来在树上以最小代 ...

  4. uoj#388. 【UNR #3】配对树(线段树合并)

    传送门 先考虑一个贪心,对于一条边来说,如果当前这个序列中在它的子树中的元素个数为奇数个,那么这条边就会被一组匹配经过,否则就不会 考虑反证法,如果在这条边两边的元素个数都是偶数,那么至少有两组匹配经 ...

  5. C. 【UNR #3】配对树

    题解: 首先可以贪心 于是问题可以等价成一条边被算当且仅当子树中个数为奇数个 题解的做法比较简单 考虑每条边,加入其子树内的点 然后为了保证区间长度为偶数 分成f0,0 f0,1 f1,0 f1,1即 ...

  6. Noip前的大抱佛脚----赛前任务

    赛前任务 tags:任务清单 前言 现在xzy太弱了,而且他最近越来越弱了,天天被爆踩,天天被爆踩 题单不会在作业部落发布,所以可(yi)能(ding)会不及时更新 省选前的练习莫名其妙地成为了Noi ...

  7. UNR#3 Day1——[ 堆+ST表+复杂度分析 ][ 结论 ][ 线段树合并 ]

    地址:http://uoj.ac/contest/45 第一题是鸽子固定器. 只会10分.按 s 从小到大排序,然后 dp[ i ][ j ][ k ] 表示前 i 个元素.已经选了 j 个.最小值所 ...

  8. GZOI 2017配对统计 树状数组

    题目 https://www.luogu.com.cn/problem/P5677 分析 最开始读题的时候没有读的太懂,以为i是在选定区间内给的,实际上不是,这道题的意思应该是在l和r的区间内找出有多 ...

  9. 51Nod 1737 配对(树的重心)

    http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1737 题意: 思路: 树的重心. 树的重心就是其所以子树的最大的子树结点 ...

随机推荐

  1. Eclipse打war包方法以及Eclipse移植项目时JDK版本不匹配Project facet Java version 1.7 is not supported

    打包时: 在项目上右键选择Export,如图: 然后选择WAR file,如图所示.接着再:其中web projecct为打出来包的名字, Destination,打包后存的位置,点击Browse.. ...

  2. http返回写入问题

    1.服务器返回写的数据全是通过response对象,response.getWriter().print(msg);这样就返回写出数据了. 比如: logger.info("encrypte ...

  3. 聚类算法K-Means, K-Medoids, GMM, Spectral clustering,Ncut

    聚类算法是ML中一个重要分支,一般采用unsupervised learning进行学习,本文根据常见聚类算法分类讲解K-Means, K-Medoids, GMM, Spectral cluster ...

  4. onfocus事件,onblur事件;Focus()方法,Blur()方法

    <1> <pre name="code" class="html"><!DOCTYPE html PUBLIC "-// ...

  5. 理解Android ANR的触发原理(转)

    一.概述 ANR(Application Not responding),是指应用程序未响应,Android系统对于一些事件需要在一定的时间范围内完成,如果超过预定时间能未能得到有效响应或者响应时间过 ...

  6. Android耳机线控具体解释,蓝牙耳机button监听(仿酷狗线控效果)

    转载请注明出处:http://blog.csdn.net/fengyuzhengfan/article/details/46461253 当耳机的媒体按键被单击后.Android系统会发出一个广播.该 ...

  7. HTML5开发实战——Sencha Touch篇(1)

    学习了很多主要的Sencha Touch内容,已经了解了Sencha Touch的开发模式.接下来一段时间我们将利用Sencha Touch来进行自己的web应用构建. 先要解决的是前端的问题.从最简 ...

  8. JQuery实现表格行的上移、下移、删除、增加

    <%@ page language="java" import="java.util.*" pageEncoding="GBK"%&g ...

  9. GET和POST 编码和乱码

    1.  什么是URL编码. URL编码是一种浏览器用来打包表单输入的格式,浏览器从表单中获取所有的name和其对应的value,将他们以name/value编码方式作为URL的一部分或者分离的发送到服 ...

  10. Jboss

    是一个基于J2EE的开放源代码的应用服务器. JBoss代码遵循LGPL许可,可以在任何商业应用中免费使用,而不用支付费用.JBoss是一个管理EJB的容器和服务器,支持EJB 1.1.EJB 2.0 ...