题解 [ZJOI2019]语言
题目大意
给出一个 \(n\) 个点的树,现在有 \(m\) 次操作,每次可以选择一个链 \(s,t\),,然后这条链上每个点都会增加一个相同属性,问对于每一个点有与它相同属性的有多少个点的答案之和。
\(n,m\le10^5\)
思路
你发现对于每一个点计算的时候答案其实就是所有包含它的链的两端虚树大小。
于是问题就是如何求虚树大小,你发现如果按 \(\text{dfs}\) 序进行排序那么答案就是:
\]
然后你发现我们这个问题就可以树上差分然后线段树合并解决了,具体见代码。
\(\texttt{Code}\)
#include <bits/stdc++.h>
using namespace std;
#define Int register int
#define MAXN 100005
template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);}
template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}
long long ans;
vector <int> G[MAXN],del[MAXN];
int n,m,tot,rt[MAXN],dfn[MAXN],par[MAXN][21],dep[MAXN];
void dfs (int u,int fa){
par[u][0] = fa,dfn[u] = ++ tot;
for (Int i = 1;i <= 20;++ i) par[u][i] = par[par[u][i - 1]][i - 1];
for (Int v : G[u]) if (v ^ fa) dep[v] = dep[u] + 1,dfs (v,u);
}
int getlca (int u,int v){
if (dep[u] < dep[v]) swap (u,v);
for (Int dis = dep[u] - dep[v],i = 20;~i;-- i) if (dis >> i & 1) u = par[u][i];
if (u == v) return u;
else{
for (Int i = 20;~i;-- i) if (par[u][i] ^ par[v][i]) u = par[u][i],v = par[v][i];
return par[u][0];
}
}
struct Segment{
#define MAXM MAXN*60
int cnt,ls[MAXM],rs[MAXM],t[MAXM],s[MAXM],c[MAXM],f[MAXM];
//t维护的是dfn最大的,s是dfn是最小的
int query (int u){return f[u] - dep[getlca (s[u],t[u])];}
void Pushup (int u){
f[u] = f[ls[u]] + f[rs[u]] - dep[getlca (t[ls[u]],s[rs[u]])];
t[u] = t[rs[u]] ? t[rs[u]] : t[ls[u]],
s[u] = s[ls[u]] ? s[ls[u]] : s[rs[u]];
}
void modify (int &u,int l,int r,int p,int x){
if (!u) u = ++ cnt;
if (l == r){
c[u] += x,f[u] = c[u] ? dep[p] : 0,t[u] = s[u] = c[u] ? p : 0;
return ;
}
int mid = (l + r) >> 1;
if (dfn[p] <= mid) modify (ls[u],l,mid,p,x);
else modify (rs[u],mid + 1,r,p,x);
Pushup (u);
}
void Merge (int &u,int v,int l,int r){//学习巨佬的方法可以省空间
if (!u || !v) return u |= v,void ();
if (l == r){
c[u] += c[v],f[u] |= f[v],s[u] |= s[v],t[u] |= t[v];
return ;
}
int mid = (l + r) >> 1;
Merge (ls[u],ls[v],l,mid),Merge (rs[u],rs[v],mid + 1,r);
Pushup (u);
}
}Tree;
void Solve (int u){
for (Int v : G[u]) if (v ^ par[u][0]) Solve (v);
for (Int v : del[u]) Tree.modify (rt[u],1,n,v,-1);
ans += Tree.query (rt[u]),Tree.Merge (rt[par[u][0]],rt[u],1,n);
}
signed main(){
read (n,m);
for (Int i = 2,u,v;i <= n;++ i) read (u,v),G[u].push_back (v),G[v].push_back (u);
dfs (1,0);for (Int i = 1,u,v,lca;i <= m;++ i){
read (u,v),lca = getlca (u,v);
Tree.modify (rt[u],1,n,u,1),Tree.modify (rt[u],1,n,v,1);
Tree.modify (rt[v],1,n,u,1),Tree.modify (rt[v],1,n,v,1);
del[lca].push_back (u),del[lca].push_back (v);
del[par[lca][0]].push_back (u),del[par[lca][0]].push_back (v);
}
Solve (1),write (ans >> 1),putchar ('\n');
return 0;
}
题解 [ZJOI2019]语言的更多相关文章
- 题解 P5327 [ZJOI2019]语言
P5327 [ZJOI2019]语言 解题思路 暴力 首先讲一下我垃圾的 40pts 的暴力(其他 dalao 都是 60pts 起步): 当然评测机快的话(比如 LOJ 的),可以卡过 3,4 个点 ...
- 【题解】Luogu P5327 [ZJOI2019]语言
原题传送门 看到这种树上统计点对个数的题一般是线段树合并,这题也不出意外 先对这棵树进行树剖,对于每次普及语言,在\(x,y\)两点的线段树上的\(x,y\)两位置打\(+1\)标记,在点\(fa[l ...
- P5327 [ZJOI2019]语言
一边写草稿一边做题吧.要看题解的往下翻,或者是旁边的导航跳一下. 草稿 因为可以开展贸易活动的条件是存在一种通用语 \(L\) 满足 \(u_i\) 到 \(v_i\) 的最短路径上都会 \(L\) ...
- PC/UVa 题号: 110106/10033 Interpreter (解释器)题解 c语言版
, '\n'); #include<cstdio> #include<iostream> #include<string> #include<algorith ...
- [ZJOI2019]语言
树链剖分入门题吧 一个非常直观的想法是使用树剖将一条链拆成\(log^2n\)个矩形,套用矩形面积并算法即可得到一个垃圾的3个log过不去算法 为了得到一个两个log的做法,我们观察一下拆出来的矩形的 ...
- [ZJOI2019]语言[树链的并、线段树合并]
题意 题目链接 分析 考虑枚举每个点的答案,最后除以 2 即可. 可以与 \(u\) 构成合法点对 的集合 为所有经过了 \(u\) 的链的并.因为这些链两两有交,根据结论 "树上两条相交的 ...
- Luogu P5327 [ZJOI2019]语言
ZJOI2019Day2的温暖题,然后考场上只会大常数的\(O(n\log^3 n)\),就懒得写拿了60pts走人 首先我们简化题意,容易发现每个点能到达的点形成了一个联通块,我们只需要统计出这个联 ...
- [Luogu5327][ZJOI2019]语言(树上差分+线段树合并)
首先可以想到对每个点统计出所有经过它的链的并所包含的点数,然后可以直接得到答案.根据实现不同有下面几种方法.三个log:假如对每个点都存下经过它的链并S[x],那么每新加一条路径进来的时候,相当于在路 ...
- Luogu5327 ZJOI2019语言(树上差分+线段树合并)
暴力树剖做法显然,即使做到两个log也不那么优美. 考虑避免树剖做到一个log.那么容易想到树上差分,也即要对每个点统计所有经过他的路径产生的总贡献(显然就是所有这些路径端点所构成的斯坦纳树大小),并 ...
随机推荐
- 在按照ROS官方步骤操作,同时用Git管理整个过程,git clone的新catkin_ws报错: catkin_package() include dir 'include' does not exist relative to
在按照ROS官方步骤操作,同时用Git管理整个过程,git clone的新catkin_ws报错如下: CMake Error at /opt/ros/kinetic/share/catkin/cma ...
- JavaScript——数组——数组长度
JavaScript--数组--数组长度 JavaScript中的数组长度是可变的,可用赋值运算符改变数组大小,如果改变之后的数组的长度比原数组大,则新数组会在末尾补充相应数量的空位,空位上的数组元素 ...
- QT学习日记篇-02-QT信号和槽
课程大纲: <1>给控件改名字 随着UI界面的控件变多,如果使用系统自带的名称,后期会让人不明觉厉,说白了,就是掌握C++的命名规则:易懂,条例清晰,人性化 方法:直接点击控件,进入右侧对 ...
- 假期作业02:安装JDK与文本编辑器并编写第一个Java程序
假期作业02:安装JDK与文本编辑器并编写第一个Java程序 一.安装JDK与文本编辑器并编写第一个java程序 首先在oracle官网(需要创建账号,进行登录后方可使用)按照自己的需求下载JDK(h ...
- K8S资源编排(yaml)
1.yaml的格式 2.yaml的组成部分 3.yaml常用字段的含义 4.yaml编写方式 (1)方式一:使用kubectl create命令生成yaml文件,然后修改 (2)方式2:在已经部署好的 ...
- Jenkins(4)- 在centos7.x下完全卸载Jenkins
如果想从头学起Jenkins的话,可以看看这一系列的文章哦 https://www.cnblogs.com/poloyy/category/1645399.html 先关闭tomcat ./shutd ...
- Spring全自动AOP和项目加入jar包
一.jar可以引进项目中,复制到路下后,要add as library,加载到工作空间中才能引入: 也jar包放在硬盘的项目目录外面,可以多个项目引入共用: 二.xml配置 1.aop全自动配置 2. ...
- 硕盟USB3.0 转RJ45千兆网卡 TYPE A USB3.0 TO RJ45
硕盟SM-A44是一款USB3.0转RJ45千兆网口转换器.这是一种高性能和低开销的解决方案.转换USB端口到10 / 100/ 1000M以太网端口可以让您的笔记本,台式机电脑能够通过USB接口连接 ...
- Java比较两个浮点数
浮点数的基本数据类型不能用==比较,包装数据类型不能用 equals 比较 浮点数的表示 在计算机系统中,浮点数采用 符号+阶码+尾数 进行表示.在Java中,单精度浮点数float类型占32位,它的 ...
- POJ1426——Find The Multiple
POJ1426--Find The Multiple Description Given a positive integer n, write a program to find out a non ...