传送门

先考虑一个贪心,对于一条边来说,如果当前这个序列中在它的子树中的元素个数为奇数个,那么这条边就会被一组匹配经过,否则就不会

考虑反证法,如果在这条边两边的元素个数都是偶数,那么至少有两组匹配经过它,那么把这两条路径都删去这条边可以更优。如果两边是奇数,一定至少有一条路径经过它,去掉这组匹配之后就变成了偶数的情况。证毕

然后是一个神仙的转化,我们对于一颗子树中的元素,在序列里标记为\(1\),否则为\(0\),那么这条边出现次数就是序列中长度为偶数且区间和为奇数的区间个数

考虑用线段树合并优化,对于每个节点,记\(t[p][0/1][0/1]\)表示节点\(p\)代表的区间中前缀和为偶数\(/\)奇数,下标为偶数\(/\)奇数的下标个数,然后线段树合并就行了

然而咱还是搞不明白为啥线段树上的区间要设为\([1,m+1]\)……有哪位知道为什么的请告诉咱一声……

//minamoto
#include<bits/stdc++.h>
#define R register
#define fp(i,a,b) for(R int i=a,I=b+1;i<I;++i)
#define fd(i,a,b) for(R int i=a,I=b-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
using namespace std;
char buf[1<<21],*p1=buf,*p2=buf;
inline char getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
int read(){
R int res,f=1;R char ch;
while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1);
for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0');
return res*f;
}
const int N=1e5+5,M=N<<5,P=998244353;
inline int add(R int x,R int y){return x+y>=P?x+y-P:x+y;}
inline int dec(R int x,R int y){return x-y<0?x-y+P:x-y;}
inline int mul(R int x,R int y){return 1ll*x*y-1ll*x*y/P*P;}
int ksm(R int x,R int y){
R int res=1;
for(;y;y>>=1,x=mul(x,x))if(y&1)res=mul(res,x);
return res;
}
struct eg{int v,nx,w;}e[N<<1];int head[N],tot;
inline void add_edge(R int u,R int v,R int w){e[++tot]={v,head[u],w},head[u]=tot;}
int sum[M],ls[M],rs[M],t[M][2][2],rt[N];
int n,m,ans,cnt,u,v,w;
void upd(int p,int l,int r){
sum[p]=0;
if(ls[p])sum[p]+=sum[ls[p]];
if(rs[p])sum[p]+=sum[rs[p]];
int x=ls[p]?sum[ls[p]]&1:0;
fp(i,0,1)fp(j,0,1){
t[p][i][j]=0;
if(ls[p])t[p][i][j]+=t[ls[p]][i][j];
if(rs[p])t[p][i][j]+=t[rs[p]][i^x][j];
}
int mid=(l+r)>>1;
if(!ls[p])t[p][0][0]+=(mid>>1)-((l-1)>>1),t[p][0][1]+=((mid+1)>>1)-(l>>1);
if(!rs[p])t[p][x][0]+=(r>>1)-(mid>>1),t[p][x][1]+=((r+1)>>1)-((mid+1)>>1);
}
void ins(int &p,int l,int r,int x){
if(!p){
p=++cnt;
t[p][0][0]=(r>>1)-((l-1)>>1);
t[p][0][1]=((r+1)>>1)-(l>>1);
}
if(l==r)return ++sum[p],void();
int mid=(l+r)>>1;
x<=mid?ins(ls[p],l,mid,x):ins(rs[p],mid+1,r,x);
upd(p,l,r);
}
int merge(int x,int y,int l,int r){
if(!x||!y)return x|y;
int mid=(l+r)>>1;
ls[x]=merge(ls[x],ls[y],l,mid);
rs[x]=merge(rs[x],rs[y],mid+1,r);
upd(x,l,r);
return x;
}
void dfs(int u,int fa){
go(u)if(v!=fa){
dfs(v,u);
ans=add(ans,mul(e[i].w,1ll*t[rt[v]][0][0]*t[rt[v]][1][0]%P+1ll*t[rt[v]][0][1]*t[rt[v]][1][1]%P));
rt[u]=merge(rt[u],rt[v],1,m+1);
}
}
int main(){
// freopen("testdata.in","r",stdin);
n=read(),m=read();
fp(i,1,n-1)u=read(),v=read(),w=read(),add_edge(u,v,w),add_edge(v,u,w);
fp(i,1,m)u=read(),ins(rt[u],1,m+1,i);
dfs(1,0);
printf("%d\n",ans);
return 0;
}

uoj#388. 【UNR #3】配对树(线段树合并)的更多相关文章

  1. UOJ #164 [清华集训2015]V (线段树)

    题目链接 http://uoj.ac/problem/164 题解 神仙线段树题. 首先赋值操作可以等价于减掉正无穷再加上\(x\). 假设某个位置从前到后的操作序列是: \(x_1,x_2,..., ...

  2. 浅谈树套树(线段树套平衡树)&学习笔记

    0XFF 前言 *如果本文有不好的地方,请在下方评论区提出,Qiuly感激不尽! 0X1F 这个东西有啥用? 树套树------线段树套平衡树,可以用于解决待修改区间\(K\)大的问题,当然也可以用 ...

  3. [UOJ UNR#1]奇怪的线段树

    来自FallDream的博客,未经允许,请勿转载, 谢谢. 原题可以到UOJ看,传送门 如果存在一个点是白的,却有儿子是黑的,显然无解. 不然的话,只要所有黑色的“黑叶子”节点,即没有黑色的儿子的节点 ...

  4. UOJ#7. 【NOI2014】购票 | 线段树 凸包优化DP

    题目链接 UOJ #7 题解 首先这一定是DP!可以写出: \[f[i] = \min_{ancestor\ j} \{f[j] + (d[j] - d[i]) * p[i] + q[i]\}\] 其 ...

  5. UOJ #314. 【NOI2017】整数 | 线段树 压位

    题目链接 UOJ 134 题解 可爱的电音之王松松松出的题--好妙啊. 首先想一个朴素的做法! 把当前的整数的二进制当作01序列用线段树维护一下(序列的第i位就是整数中位权为\(2^k\)的那一位). ...

  6. 【uoj#228】基础数据结构练习题 线段树+均摊分析

    题目描述 给出一个长度为 $n$ 的序列,支持 $m$ 次操作,操作有三种:区间加.区间开根.区间求和. $n,m,a_i\le 100000$ . 题解 线段树+均摊分析 对于原来的两个数 $a$ ...

  7. UOJ#470. 【ZJOI2019】语言 虚树,线段树合并

    原文链接www.cnblogs.com/zhouzhendong/p/UOJ470.html 前言 做完情报中心来看这个题突然发现两题有相似之处然后就会做了. 题解 首先,我们考虑将所有答案点对分为两 ...

  8. UOJ#299. 【CTSC2017】游戏 线段树 概率期望 矩阵

    原文链接www.cnblogs.com/zhouzhendong/p/UOJ299.html 前言 不会概率题的菜鸡博主做了一道概率题. 写完发现运行效率榜上的人都没有用心卡常数——矩阵怎么可以用数组 ...

  9. UOJ#467. 【ZJOI2019】线段树 线段树,概率期望

    原文链接www.cnblogs.com/zhouzhendong/p/ZJOI2019Day1T2.html 前言 在LOJ交了一下我的代码,发现它比选手机快将近 4 倍. 题解 对于线段树上每一个节 ...

  10. 【BZOJ-3306】树 线段树 + DFS序

    3306: 树 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 792  Solved: 262[Submit][Status][Discuss] De ...

随机推荐

  1. Java for LeetCode 138 Copy List with Random Pointer

    A linked list is given such that each node contains an additional random pointer which could point t ...

  2. Git如何强制拉取一个远程分支到本地分支(转载)

    有时候,我们在使用git pull指令想把一个远程分支拉取到本地分支的时候,老是会拉取失败,这一般是因为某种原因,本地分支和远程分支的内容差异无法被git成功识别出来,所以git pull指令什么都不 ...

  3. wamp server 安装后 Apache80端口占用

    提示:Your port 80 is actually used by :Server: Microsoft-HTTPAPI/2.0 解决方案:计算机->右键管理->服务和应用程序-> ...

  4. LightOJ - 1395 A Dangerous Maze (II) —— 期望

    题目链接:https://vjudge.net/problem/LightOJ-1395 1395 - A Dangerous Maze (II)    PDF (English) Statistic ...

  5. Codeforces 854B Maxim Buys an Apartment:贪心

    题目链接:http://codeforces.com/contest/854/problem/B 题意: 有n栋房子从1到n排成一排,有k栋房子已经被售出. 现在你要买一栋“好房子”. 一栋房子是“好 ...

  6. nginx websocket

    前两天折腾了下socketio,部署完发现通过nginx代理之后前端的socket无法和后端通信了,于是暴查一通,最后解决问题: location / { proxy_pass http://127. ...

  7. T57

    “期待使我产生了介于幸福与恐惧之间的激动”The anticipation produced in me a sensation somewhat between bliss and fear他猛一下 ...

  8. django-crontab 定时执行任务方法

    需求 每天请求一封邮件,并读取该邮件 这个其实可以使用linux 自带了crontab实现,但是毕竟是django 开发.想着不知道有没有方法可以从django 中实现. 简单搜索了下,这方面的方法确 ...

  9. bzoj 1119 [POI2009] SLO & bzoj 1697 牛排序 —— 置换+贪心

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1119 https://www.lydsy.com/JudgeOnline/problem.p ...

  10. poj3254二进制放牛——状态压缩DP

    题目:http://poj.org/problem?id=3254 利用二进制压缩状态,每一个整数代表一行的01情况: 注意预处理出二进制表示下没有两个1相邻的数的方法,我的方法(不知为何)错了,看到 ...