不愧是 \(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. Python版本与Jupyter记录

    最近使用Python的时候,遇到一个版本问题.我本地安装的Python版本是3.8.0,在使用match...case...语法时,提示如下报错: 查询之后,才知晓3.8.0还没有match语法,ma ...

  2. YashanDB演讲实录|别彬彬:金融科技对智能化创新系统的机遇与路径

    本文为"2024国产数据库创新生态大会"深算院采石矶.钓鱼城系统技术总监别彬彬的演讲实录分享,主题为 <金融科技对智能化创新系统的机遇与路径>,欢迎阅读. 各位领导.嘉 ...

  3. nodejs版本控制器nvm安装及简单使用

    介绍:nvm是node.js的版本管理器,可以安装和切换不同版本node.js 下载:https://github.com/coreybutler/nvm-windows/releases 官网下载: ...

  4. 某开源ERP最新版SQL与RCE的审计过程

    文章首发于 https://forum.butian.net/share/134 前言 代码路径 https://gitee.com/jishenghua/JSH_ERP 软件版本 华夏ERP_v2. ...

  5. 如何为在线客服系统的 Web Api 后台主程序添加 Bootstrap 启动页面

    背景 我在业余时间开发了一款自己的独立产品:升讯威在线客服与营销系统.这个系统的核心后台主程序,在最早期是完全没有页面,经常有朋友部署之后,一访问是 404,以为没有部署成功.我一看这肯定不行啊,可后 ...

  6. 如何使用图片压缩降低COS流量成本?

    导语 本文将介绍如何通过[图片压缩]能力,让您降本增效的使用 COS ,文章将写得浅显易懂,旨在快速带领用户了解图片压缩的用法及带来的收益. **** 图片压缩为什么会让您降本增效?******** ...

  7. startup

    要提取startup/后面的字符,可以使用cut命令或awk命令.以下是两种方法: 使用cut命令: bash #!/bin/bash # 给定的字符串 STR1="startup/valu ...

  8. shell 将文件内容读取到 数组中

    #!/bin/bash prod_file=/home/vmuser/linbo/kettleDemo/job/test/CA-20201224.csv test_file=/home/vmuser/ ...

  9. grpc与http2的关系

    https://nullget.sourceforge.io/?q=node/895 grpc与http2的关系 grpc client 发送包到原生的http2 server client收到报错: ...

  10. Qt编写安防视频监控系统52-颜色配置

    一.前言 在系统打印日志或者窗口信息栏中,各种临时打印信息都显示在这里,很多时候我们还需要对特定的类别的信息突出颜色显示,比如告警信息,甚至对不同的告警级别的信息还可以分别不同的颜色显示,这样看起来会 ...