不愧是 \(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. canvas(八)绘制图片和坐标转换

    1.绘制图片 相关api及其参数:ctx.drawImage() 参数 说明 参数一 图片对象 参数二,三 可选,图片裁剪的基点(原图左上角为原点) 参数四,五 可选,图片裁剪区域的宽高(基于原图大小 ...

  2. C#日期类型转化总结【转化,农历,节气,星期】

    转为日期类型 将8位日期字符串转换为日期格式 dateStr = "20220203"; System.IFormatProvider format=new System.Glob ...

  3. Ant Design Pro项目ProTable怎么获取搜索表单值

    前情 公司有经常需要做一些后台管理页面,我们选择了Ant Design Pro,它是基于 Ant Design 和 umi 的封装的一整套企业级中后台前端/设计解决方案. 产品效果图 最新接到的一个后 ...

  4. OS之《机械硬盘》

    数据的组织 一个磁盘设备 ---->多个物理盘片 一个物理盘片---->正反两面存储面 一个存储面---->多个磁道(每个磁道上存储容量时一样的,可存储相同数目的二进制位),所以,内 ...

  5. angr-ctf

    angr 的项目地址 https://github.com/jakespringer/angr_ctf angr实战 00 拖到IDA 就是输入正确的指令才能通关 这次试一下用angr来解题 goah ...

  6. 内网穿透之http代理服务器

    在公网访问内网http服务可以用内网穿透工具,例如frp和nps等优秀工具.但我发现这类工具会在服务器启动不止一个端口,对于有些网络审查来说很容易发现在进行内网穿透.因此我想是否可以只在服务器启动一个 ...

  7. java.time 的纪年方式

    Date date = new Date(); Instant instant = date.toInstant(); Chronology chronology = HijrahChronology ...

  8. 各版本jdk百度云下载,包括linux版和windows版

    并不是越新的版本就一定越好,请先考虑jdk的版本是否跟你的开发环境有版本冲突问题. 2021-11-4更新 ps:从官网下载实在是太慢了!! 官网链接:https://www.oracle.com/j ...

  9. 从 ftp 上下载文件、文件夹

    下载子文件夹: wget -r -nH --cut-dir=1 ftp://ip/folder_name/ 下载压缩文件: wget ftp://ip/folder_name/folder_name/ ...

  10. 优化大宽表查询性能,揭秘GaussDB(DWS) 谓词列analyze

    本文分享自华为云社区<GaussDB(DWS) 谓词列analyze揭秘>,作者:SmithCoder. 1. 前言 适用版本:[9.1.0.100(及以上)] ​当前GaussDB(DW ...