传送门

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

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

然后是一个神仙的转化,我们对于一颗子树中的元素,在序列里标记为\(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;
}

转载于:https://www.cnblogs.com/bztMinamoto/p/10286479.html

uoj#388. 【UNR #3】配对树(线段树合并)相关推荐

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

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

  2. 树套树-线段树套平衡树

    作用 线段树的作用是区间修改和查询,平衡树的作用是查询第k大,k的排名,前驱,后继.这两个结合起来,就变成了可以区间修改和查询第k大,k的排名,前驱,后继的数据结构:树套树-线段树套平衡树. 实现 先 ...

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

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

  4. 线段树 ---- 线段树维护线段相加+滑动变长窗口 2021牛客多校第7场 F xay loves trees

    题目大意: 给你两个大小相同的树但是形状不一定一样 叫你选出最大的子集,满足下面两个条件 在第一颗树上是一条链 在第二颗树上任意两个点都不是祖先关系 解题思路: 首先我们现在第二颗树上面把每个点的df ...

  5. BZOJ 3685: 普通van Emde Boas树( 线段树 )

    建颗权值线段树就行了...连离散化都不用... 没加读入优化就TLE, 加了就A掉了...而且还快了接近1/4.... ---------------------------------------- ...

  6. 2021CCPC(桂林) - Suffix Automaton(后缀树+线段树)

    题目链接:点击查看 题目大意:给出一个长度为 nnn 的字符串,再给出 qqq 次询问,每次询问需要输出本质不同第 kkk 小的子串的起止位置.如果有多个答案,输出起点最小的那个. 本题规定字符串大小 ...

  7. 牛客 - sequence(笛卡尔树+线段树)

    题目链接:点击查看 题目大意:给出一个长度为 n 的数列 a 和数列 b ,求 题目分析:不算难的题目,对于每个 a[ i ] 求一下贡献然后维护最大值就好,具体思路就是,先找出每个 a[ i ] 左 ...

  8. HDU - 4417 Super Mario(主席树/线段树+离线)

    题目链接:点击查看 题目大意:给出由 n 个数的数列,再给出 m 次查询,每次查询需要输出 [ l , r ] 内小于等于 h 的数有多少个 题目分析:大晚上睡不着觉随便做做题,发现这个题目原来可以用 ...

  9. YbtOJ#752-最优分组【笛卡尔树,线段树】

    正题 题目链接:http://www.ybtoj.com.cn/problem/752 题目大意 nnn个人,每个人有cic_ici​和did_idi​分别表示这个人所在的队伍的最少/最多人数. 然后 ...

  10. P4755-Beautiful Pair【笛卡尔树,线段树】

    正题 题目链接:https://www.luogu.com.cn/problem/P4755 题目大意 nnn个数字的一个序列,求有多少个点对i,ji,ji,j满足ai×aj≤max{ak}(k∈[l ...

最新文章

  1. 十三、序列化和反序列化(部分转载)
  2. 赛门铁克发布针对WannaCry勒索软件的更新预警
  3. 利用SqlHelper.cs实现Web程序对数据库的增、删、改等操作
  4. COCO数据集数据转换为XML格式
  5. 优米网:创业传记——傅盛
  6. 小酌重构系列[19]——分解大括号
  7. 安卓开发真机遇到Failed to install Spaceassault.apk on device 'HT1CKV205198': timeout 测试机没有问题...
  8. linux课程设计qq,仿QQ聊天系统课程设计.doc
  9. 项目管理之码云和git
  10. RocketMQ项目rocketmq-externals中rocketmq-console启动报错
  11. c#仿QQ安全管家事例(附:源码下载)
  12. 嵌套高度问题_excel查找技巧:嵌套函数在区间查找中的应用解析
  13. table 条数过大优化_MySQL数据库优化的介绍(图文)
  14. 安卓最新版本_nyearlabel安卓下载-nyearlabel最新版本下载v1.2.3 安卓版
  15. 华为手机应用程序变为Android图标,华为手机如何改变应用图标
  16. EasyAR初学者教程
  17. python编写一个函数把华氏温度转换成摄氏温度_编写一个函数把华氏温度转换成摄氏温度,温度转换公式为:c=(f-32)*5/9。在主函数中输入华氏温度值......
  18. 通过蒲公英快速查询苹果手机UDID方法
  19. win10打开计算机黑屏怎么办,win10开机黑屏原因【解决方法】
  20. 为什么在CAD图纸中插入外部参照后会出现多余图形?

热门文章

  1. Java程序员的典型工作过程有哪些_Java程序员都要经历哪些阶段
  2. jfinal java搭建_Eclipse快速搭建Jfinal web应用 (一)
  3. python递归必须要有_python如何递归生成树?
  4. html 输入框从左上角,在输入框的左上角,使文本开始_input_开发99编程知识库
  5. c++ for循环 流程图_python 零基础必知--条件控制与循环语句
  6. c语言volatile_[技术]为什么单片机C语言编程时某一变量有时乱码
  7. C语言代码规范(十)花里胡哨代码鉴赏
  8. 图灵计算机模型意义,图灵机有什么意义_学习图灵机模型中遇到的问题
  9. boost windows编译
  10. gcc 编译器使用指南