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

题面

UOJ

题解

考虑一个固定区间怎么计算答案,把这些点搞下来建树,然后\(dp\),不难发现一个点如果子树内能够匹配的话就一定会匹配完,所以\(dp\)可以做到线性。

那么根据上面的\(dp\)方式,一条边会被匹配到,当且仅当把这条边删掉之后,两个连通块内分别有奇数个目标点。那么如果我们考虑枚举每一条边,然后把子树内的点给标记一下,于是变成了在原序列上求有多少个偶数区间满足有偶数个点被标记,这个问题可以做一个前缀和,把奇偶位置拆开,于是答案就是两个位置中的奇数个数乘上偶数个数。这个过程可以拿线段树维护。

接下来就变成每次要标记子树中的所有点,每次暴力显然不合理。

改成\(dsu\)这个复杂度就很合理了。这个复杂度似乎是两个\(log\)的。

#include<iostream>
#include<cstdio>
#include<vector>
using namespace std;
#define MAX 100100
#define MOD 998244353
inline int read()
{
int x=0;bool t=false;char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=true,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return t?-x:x;
}
int n,m,ans;
struct Line{int v,next,w;}e[MAX<<1];
int h[MAX],cnt=1;
inline void Add(int u,int v,int w){e[cnt]=(Line){v,h[u],w};h[u]=cnt++;}
int wf[MAX],sz[MAX],hson[MAX];
void dfs1(int u,int ff)
{
sz[u]=1;
for(int i=h[u];i;i=e[i].next)
{
int v=e[i].v;if(v==ff)continue;
wf[v]=e[i].w;dfs1(v,u);sz[u]+=sz[v];
if(sz[v]>sz[hson[u]])hson[u]=v;
}
}
#define lson (now<<1)
#define rson (now<<1|1)
struct Node{int s[2][2],r;}t[MAX<<2];
void pushup(int now)
{
t[now].s[0][0]=(t[lson].s[0][0]+t[rson].s[0][0])%MOD;
t[now].s[0][1]=(t[lson].s[0][1]+t[rson].s[0][1])%MOD;
t[now].s[1][0]=(t[lson].s[1][0]+t[rson].s[1][0])%MOD;
t[now].s[1][1]=(t[lson].s[1][1]+t[rson].s[1][1])%MOD;
}
void Build(int now,int l,int r)
{
if(l==r){t[now].s[l&1][0]+=1;return;}
int mid=(l+r)>>1;
Build(lson,l,mid);
Build(rson,mid+1,r);
pushup(now);
}
void putrev(int now)
{
swap(t[now].s[0][0],t[now].s[0][1]);
swap(t[now].s[1][0],t[now].s[1][1]);
t[now].r^=1;
}
void pushdown(int now)
{
if(!t[now].r)return;
putrev(lson);putrev(rson);
t[now].r^=1;
}
void Modify(int now,int l,int r,int L,int R)
{
if(L<=l&&r<=R){putrev(now);return;}
int mid=(l+r)>>1;pushdown(now);
if(L<=mid)Modify(lson,l,mid,L,R);
if(R>mid)Modify(rson,mid+1,r,L,R);
pushup(now);
}
vector<int> V[MAX];
bool vis[MAX];
void upd(int u,int ff)
{
for(int v:V[u])Modify(1,0,m,v,m);
for(int i=h[u];i;i=e[i].next)
if(e[i].v!=ff&&!vis[e[i].v])upd(e[i].v,u);
}
void dfs(int u,int ff,int tp)
{
for(int i=h[u];i;i=e[i].next)
if(e[i].v!=ff&&e[i].v!=hson[u])
dfs(e[i].v,u,0);
if(hson[u])dfs(hson[u],u,1),vis[hson[u]]=true;
upd(u,ff);
int cnt=(1ll*t[1].s[0][0]*t[1].s[0][1]+1ll*t[1].s[1][0]*t[1].s[1][1])%MOD;
ans=(ans+1ll*cnt*wf[u])%MOD;
vis[hson[u]]=false;
if(!tp)upd(u,ff);
}
int main()
{
n=read();m=read();
for(int i=1;i<n;++i)
{
int u=read(),v=read(),w=read();
Add(u,v,w);Add(v,u,w);
}
for(int i=1;i<=m;++i)V[read()].push_back(i);
Build(1,0,m);dfs1(1,0);dfs(1,0,0);
printf("%d\n",ans);
return 0;
}

【UOJ#388】【UNR#3】配对树(线段树,dsu on tree)的更多相关文章

  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. WPF ListBox 隐藏滑块

    <ListBox ScrollViewer.VerticalScrollBarVisibility = "Disabled"; </ListBox>

  2. LinuxShell脚本——认识Shell脚本

    LinuxShell脚本——认识Shell脚本 摘要:本文主要介绍了Shell脚本的一些基本知识. 什么是Shell脚本 shell脚本是利用shell的功能所写的一个程序,这个程序是使用纯文本文件, ...

  3. 【转载】更简单的学习Android事件分发

    事件分发是Android中非常重要的机制,是用户与界面交互的基础.这篇文章将通过示例打印出的Log,绘制出事件分发的流程图,让大家更容易的去理解Android的事件分发机制. 一.必要的基础知识 1. ...

  4. vue中点击按钮复制内容

    <el-button type="primary" round size="mini" @click="copyUrl">复制u ...

  5. python从入门到放弃之协程

    协程 协程,又称微线程,纤程.英文名Coroutine. 协程的概念很早就提出来了,但直到最近几年才在某些语言(如Lua)中得到广泛应用. 子程序,或者称为函数,在所有语言中都是层级调用,比如A调用B ...

  6. RabbitMQ获取队列的消息数目

    使用RabbitMQ,业务需求,想要知道队列中还有多少待消费待数据. 方式一: @Value("${spring.rabbitmq.host}") private String h ...

  7. postman---postman简单介绍

    有小伙伴们想要了解postman,今天它来了,不要问它到底有多强大,自古免费好用即是王道,它不仅仅是开发接口强大的调试工具,还是测试接口的居家必备,它不仅仅可以把需要调用的接口保存下来方便调用,还可以 ...

  8. python函数内容

    在刚接触python的时候就有个疑问,什么是函数? python语言的函数和数学语言的函数有区别吗? 什么是函数 数学函数:给定一个数集A,假设其中的元素为x.现对A中的元素x施加对应法则f,记作f( ...

  9. (六)Amazon Lightsail 部署LAMP应用程序之升级到Amazon EC2

    升级到Amazon EC2 将Amazon Lightsail实例升级为Amazon EC2 您将进行以下操作: ①创建使用 Amazon RDS的Web前端实例的快照 ②将该快照导出到 Amazon ...

  10. Monkey小白入门篇

    一.monkey简介 中文名:猴子 职业:压力测试小工具 用途:对待测Android应用程序进行压力测试,测试app是否会crash Android官方描述: The Monkey is a prog ...