不愧是 \(ZJOI\),《最可做的一道题》都让人一头雾水……


首先将问题转化到链上。

可以将总共的组数转化为每个点可以到达的城市。

明显给每个点建一棵动态开点线段树,维护可以和他通商的点。很明显,可以通商的点的标号连续的一段。我们可以将可以将每一次传播语言的工作当作区间修改,很明显可以用差分。最后再用线段树合并从后往前计算出每一个点的答案。

那假如问题转化到树上呢?

众所周知,假如我们想要让一棵树变成多个 木棍 链,树链剖分就是我们要熟悉掌握的一个知识点。

用树链剖分的方法,就可以最多进行 \(\log_2n\) 次操作,将所有本次被传播语言的点加入线段树。

时间复杂度 \(O(n\log^2n)\)。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e5+5;
const int M=2e7+5;
int n,m,k,id,d;ll ans;
int h[N],to[N*2],nxt[N*2];
int ls[M],rs[M],rt[N],v[M],lb[M];
int dep[N],fa[N],sn[N];
int dfn[N],sz[N],tp[N];
struct line{int x,y;};
struct que{int x,y,z;};
vector<line>a;
vector<que>q[N];
void ad(int x,int y){
to[++k]=y;
nxt[k]=h[x];
h[x]=k;
}void push_up(int x,int l,int r){
if(lb[x]) v[x]=r-l+1;
else v[x]=v[ls[x]]+v[rs[x]];
}void add(int &p,int l,int r,int x,int y,int kk){
if(!p) p=++d;
if(x<=l&&r<=y) lb[p]+=kk;
else{
int mid=(l+r)/2;
if(x<=mid) add(ls[p],l,mid,x,y,kk);
if(y>mid) add(rs[p],mid+1,r,x,y,kk);
}push_up(p,l,r);
}int merge(int x,int y,int l,int r){
if(!x||!y) return x|y;
lb[x]+=lb[y];
if(l<r){
int mid=(l+r)/2;
ls[x]=merge(ls[x],ls[y],l,mid);
rs[x]=merge(rs[x],rs[y],mid+1,r);
}push_up(x,l,r);
return x;
}void dfs1(int x,int f){
int mx=0;
dep[x]=dep[f]+1;
sz[x]=1;fa[x]=f;
for(int i=h[x];i;i=nxt[i]){
int y=to[i];
if(y==f) continue;
dfs1(y,x);
if(sz[y]>mx){
sn[x]=y;
mx=sz[y];
}sz[x]+=sz[y];
}
}void dfs2(int x,int f){
dfn[x]=++id;tp[x]=f;
q[x].push_back({id,id,1});
if(fa[x]) q[fa[x]].push_back({id,id,-1});
if(!sn[x]) return;
dfs2(sn[x],f);
for(int i=h[x];i;i=nxt[i])
if(to[i]!=fa[x]&&to[i]!=sn[x])
dfs2(to[i],to[i]);
}int lca(int x,int y){
a.clear();
while(tp[x]!=tp[y]){
if(dep[tp[x]]<dep[tp[y]]) swap(x,y);
a.push_back({dfn[tp[x]],dfn[x]});
x=fa[tp[x]];
}if(dep[x]>dep[y]) swap(x,y);
a.push_back({dfn[x],dfn[y]});
return x;
}void solve(int x){
for(int i=h[x];i;i=nxt[i]){
int y=to[i];
if(y==fa[x]) continue;
solve(y);
rt[x]=merge(rt[x],rt[y],1,n);
}for(int i=0;i<q[x].size();i++)
add(rt[x],1,n,q[x][i].x,q[x][i].y,q[x][i].z);
ans+=v[rt[x]]-1;
}int main(){
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin>>n>>m;
for(int i=1,x,y;i<n;i++){
cin>>x>>y;
ad(x,y);ad(y,x);
}dfs1(1,0);dfs2(1,1);
while(m--){
int x,y,lc;
cin>>x>>y;
lc=fa[lca(x,y)];
for(int i=0;i<a.size();i++){
q[x].push_back({a[i].x,a[i].y,1});
q[y].push_back({a[i].x,a[i].y,1});
if(lc) q[lc].push_back({a[i].x,a[i].y,-2});
}
}solve(1);
cout<<ans/2;
return 0;
}

[ZJOI2019] 语言 题解的更多相关文章

  1. 题解 P5327 [ZJOI2019]语言

    P5327 [ZJOI2019]语言 解题思路 暴力 首先讲一下我垃圾的 40pts 的暴力(其他 dalao 都是 60pts 起步): 当然评测机快的话(比如 LOJ 的),可以卡过 3,4 个点 ...

  2. 【题解】Luogu P5327 [ZJOI2019]语言

    原题传送门 看到这种树上统计点对个数的题一般是线段树合并,这题也不出意外 先对这棵树进行树剖,对于每次普及语言,在\(x,y\)两点的线段树上的\(x,y\)两位置打\(+1\)标记,在点\(fa[l ...

  3. 题解 [ZJOI2019]语言

    题目传送门 题目大意 给出一个 \(n\) 个点的树,现在有 \(m\) 次操作,每次可以选择一个链 \(s,t\),,然后这条链上每个点都会增加一个相同属性,问对于每一个点有与它相同属性的有多少个点 ...

  4. P5327 [ZJOI2019]语言

    一边写草稿一边做题吧.要看题解的往下翻,或者是旁边的导航跳一下. 草稿 因为可以开展贸易活动的条件是存在一种通用语 \(L\) 满足 \(u_i\) 到 \(v_i\) 的最短路径上都会 \(L\) ...

  5. ZJOI2019 Day1 题解

    想要继续向前,就从克服内心的恐惧开始. 麻将 题意 在麻将中,我们称点数连续的三张牌或三张点数一样的成为面子,称两张点数一样的牌为对子.一副十四张麻将牌的胡牌条件是可以分成四个面子和一个对子或者分成七 ...

  6. [ZJOI2019]语言

    树链剖分入门题吧 一个非常直观的想法是使用树剖将一条链拆成\(log^2n\)个矩形,套用矩形面积并算法即可得到一个垃圾的3个log过不去算法 为了得到一个两个log的做法,我们观察一下拆出来的矩形的 ...

  7. [ZJOI2019]语言[树链的并、线段树合并]

    题意 题目链接 分析 考虑枚举每个点的答案,最后除以 2 即可. 可以与 \(u\) 构成合法点对 的集合 为所有经过了 \(u\) 的链的并.因为这些链两两有交,根据结论 "树上两条相交的 ...

  8. Luogu P5327 [ZJOI2019]语言

    ZJOI2019Day2的温暖题,然后考场上只会大常数的\(O(n\log^3 n)\),就懒得写拿了60pts走人 首先我们简化题意,容易发现每个点能到达的点形成了一个联通块,我们只需要统计出这个联 ...

  9. [Luogu5327][ZJOI2019]语言(树上差分+线段树合并)

    首先可以想到对每个点统计出所有经过它的链的并所包含的点数,然后可以直接得到答案.根据实现不同有下面几种方法.三个log:假如对每个点都存下经过它的链并S[x],那么每新加一条路径进来的时候,相当于在路 ...

  10. Luogu5327 ZJOI2019语言(树上差分+线段树合并)

    暴力树剖做法显然,即使做到两个log也不那么优美. 考虑避免树剖做到一个log.那么容易想到树上差分,也即要对每个点统计所有经过他的路径产生的总贡献(显然就是所有这些路径端点所构成的斯坦纳树大小),并 ...

随机推荐

  1. Taro微信小程序获取Tab页可视区域高度

    前情 公司有自己的小程序项目,因公司主要技术栈为react,所以选择了Taro来开发,Taro是京东出品的多端统一开发解决方案,用来开发小程序也相比用原生开发,在开发体验上好很多,而且还能使用成熟的R ...

  2. Grid 网格布局备忘录

    概述 网格布局(Grid)是最强大的 CSS 布局方案. 它将网页划分成一个个网格,可以任意组合不同的网格,做出各种各样的布局. Grid 布局与 Flex 布局有一定的相似性,都可以指定容器内部多个 ...

  3. 如何使用对象存储 COS ?七个步骤,帮你搞定!

    导语:本文将介绍新手如何使用对象存储 COS,主要面向小白用户,旨在快速带领用户了解 COS 的优势.功能.费用.接口及控制台指南. 01 什么是对象存储 腾讯云对象存储 COS(Cloud Obje ...

  4. 中电金信:The Financial-Grade Digital Infrastructure

    01 Product Introduction   The Financial-Grade Digital Infrastructure is a digitally-enabled foundati ...

  5. nginx jupyterWeb

    location /jupyterWeb/ { add_header X-Frame-Options SAMEORIGIN; add_header Access-Control-Allow-Origi ...

  6. 如何控制bean的加载顺序?

    写在前面 springboot遵从约定大于配置的原则,极大程度的解决了配置繁琐的问题.在此基础上,又提供了spi机制,用spring.factories可以完成一个小组件的自动装配功能. 在一般业务场 ...

  7. Qt音视频开发35-左右通道音量计算和音量不同范围值的转换

    一.前言 视频文件一般会有两个声音通道及左右声道,值有时候一样有时候不一样,很多场景下我们需要对其分开计算不同的音量值,在QAudioFormat中可以获取具体有几个通道,如果是一个通道,则左右通道值 ...

  8. Qt编写ffmpeg本地摄像头显示(16路本地摄像头占用3.2%CPU)

    一.前言 内核ffmpeg除了支持本地文件.网络文件.各种视频流播放以外,还支持打开本地摄像头,和正常的解析流程一致,唯一的区别就是在avformat_open_input第三个参数传入个AVInpu ...

  9. 基于实践:一套百万消息量小规模IM系统技术要点总结

    本文由公众号"后台技术汇"分享,原题"基于实践,设计一个百万级别的高可用 & 高可靠的 IM 消息系统",原文链接在文末.由于原文存在较多错误和不准确内 ...

  10. 即时通讯安全篇(十一):IM聊天系统安全手段之传输内容端到端加密技术

    本文由融云技术团队分享,原题"互联网通信安全之端到端加密技术",内容有较多修订和改动. 1.引言 在上篇<IM聊天系统安全手段之通信连接层加密技术>中,分享了关于通信连 ...