[loj3046]语言
定义$S_{i}$表示第$i$条链所包含的点的集合,$(x,y)$合法当且仅当$x\ne y$且$\exists i,\{x,y\}\subseteq S_{i}$(答案即$\frac{合法点对数}{2}$),显然后者等价于$y\in \cup_{x\in S_{i}}S_{i}$,因此合法点对数为$\sum_{x=1}^{n}|\cup_{x\in S_{i}}S_{i}|-1$
结论:$链并的大小=链端点所构成的虚树点数=\frac{按照dfs序排序后相邻(包括首尾)两点距离和}{2}+1$
前者显然,后者证明如下:
对每一条边统计经过次数,设其连结的深度较大的点为$x$,那么记$p_{i}=1$当且仅当$i$在$x$子树内(否则$p_{i}=0$),观察可得两个点$x$和$y$经过这条边当且仅当$p_{x}+p_{y}=1$
考虑dfs序的性质:每一个子树一定是一段区间,因此设端点按dfs序排序后为$a_{1},a_{2},...,a_{k}$,$S=\{i|p_{a_{i}}=1\}$一定是一段区间$[l,r]$,观察可得当$[l,r]=\emptyset$或$[l,r]=[1,k]$时该边答案为0,否则答案为2
考虑$[l,r]=\emptyset$或$[l,r]=[1,k]$的条件,即等价于这条边不在虚树上,那么$\frac{按照dfs序排序后相邻(包括首尾)两点距离和}{2}$即为边数,根据树的性质,加1即为点数
根据这个结论,将每条链差分并用线段树合并来找到所有端点,线段树上维护:1.个数(判断是否存在);2.区间最小点;3.区间最大点;4.区间相邻点距离和(最左和最右可以在外面算)即可,如果用st表维护lca可以做到$o(n\log_{2}n)$

1 #include<bits/stdc++.h>
2 using namespace std;
3 #define N 100005
4 #define mid (l+r>>1)
5 struct ji{
6 int nex,to;
7 }edge[N<<1];
8 int V,E,n,m,x,y,head[N],dfn[N],id[N],s[N],f[N][21],r[N],ls[N*100],rs[N*100],vis[N*100],mn[N*100],mx[N*100],sum[N*100];
9 long long ans;
10 void add(int x,int y){
11 edge[E].nex=head[x];
12 edge[E].to=y;
13 head[x]=E++;
14 }
15 void dfs(int k,int fa,int sh){
16 dfn[k]=++x;
17 id[x]=k;
18 s[k]=sh;
19 f[k][0]=fa;
20 for(int i=1;i<=20;i++)f[k][i]=f[f[k][i-1]][i-1];
21 for(int i=head[k];i!=-1;i=edge[i].nex)
22 if (edge[i].to!=fa)dfs(edge[i].to,k,sh+1);
23 }
24 int lca(int x,int y){
25 if (s[x]<s[y])swap(x,y);
26 for(int i=20;i>=0;i--)
27 if (s[f[x][i]]>=s[y])x=f[x][i];
28 if (x==y)return x;
29 for(int i=20;i>=0;i--)
30 if (f[x][i]!=f[y][i]){
31 x=f[x][i];
32 y=f[y][i];
33 }
34 return f[x][0];
35 }
36 int dis(int x,int y){
37 return s[x]+s[y]-2*s[lca(x,y)];
38 }
39 void up(int k){
40 mn[k]=min(mn[ls[k]],mn[rs[k]]);
41 mx[k]=max(mx[ls[k]],mx[rs[k]]);
42 sum[k]=sum[ls[k]]+sum[rs[k]];
43 if ((mx[ls[k]])&&(mn[rs[k]]<=n))sum[k]+=dis(id[mx[ls[k]]],id[mn[rs[k]]]);
44 }
45 void update(int &k,int l,int r,int x,int y){
46 if (!k){
47 k=++V;
48 mn[k]=n+1;
49 }
50 if (l==r){
51 vis[k]+=y;
52 if (vis[k]>0)mn[k]=mx[k]=l;
53 else{
54 mn[k]=n+1;
55 mx[k]=0;
56 }
57 return;
58 }
59 if (x<=mid)update(ls[k],l,mid,x,y);
60 else update(rs[k],mid+1,r,x,y);
61 up(k);
62 }
63 int merge(int k1,int k2){
64 if ((!k1)||(!k2))return k1+k2;
65 if ((!ls[k1])&&(!rs[k1])){
66 vis[k1]+=vis[k2];
67 if (vis[k1]>0){
68 mn[k1]=min(mn[k1],mn[k2]);
69 mx[k1]=max(mx[k1],mx[k2]);
70 }
71 else{
72 mn[k1]=n+1;
73 mx[k1]=0;
74 }
75 return k1;
76 }
77 ls[k1]=merge(ls[k1],ls[k2]);
78 rs[k1]=merge(rs[k1],rs[k2]);
79 up(k1);
80 return k1;
81 }
82 void dfs(int k,int fa){
83 for(int i=head[k];i!=-1;i=edge[i].nex)
84 if (edge[i].to!=fa){
85 dfs(edge[i].to,k);
86 r[k]=merge(r[k],r[edge[i].to]);
87 }
88 if (mn[r[k]]!=mx[r[k]])ans+=sum[r[k]]+dis(id[mn[r[k]]],id[mx[r[k]]]);
89 }
90 int main(){
91 scanf("%d%d",&n,&m);
92 memset(head,-1,sizeof(head));
93 for(int i=1;i<n;i++){
94 scanf("%d%d",&x,&y);
95 add(x,y);
96 add(y,x);
97 }
98 x=0;
99 dfs(1,0,1);
100 mn[0]=n+1;
101 for(int i=1;i<=m;i++){
102 scanf("%d%d",&x,&y);
103 int z=lca(x,y);
104 update(r[x],1,n,dfn[x],1);
105 update(r[x],1,n,dfn[y],1);
106 update(r[y],1,n,dfn[x],1);
107 update(r[y],1,n,dfn[y],1);
108 update(r[f[z][0]],1,n,dfn[x],-2);
109 update(r[f[z][0]],1,n,dfn[y],-2);
110 }
111 dfs(1,0);
112 printf("%lld",ans/4);
113 }
[loj3046]语言的更多相关文章
- [LOJ3046][ZJOI2019]语言:树链的并+线段树合并
分析 问题显然可以转化为对于每个节点询问所有这个节点的所有链的链并的大小. 考场上我直接通过树剖打标记+树剖线段树维护以\(O(n \log^3 n)\)的时间复杂度暴力实现了这个过程.(使用LCT或 ...
- bzoj5518 & loj3046 「ZJOI2019」语言 线段树合并+树链的并
题目传送门 https://loj.ac/problem/3046 题解 首先问题就是问有多少条路径是给定的几条路径中的一条的一个子段. 先考虑链的做法. 枚举右端点 \(i\),那么求出 \(j\) ...
- C语言 · 高精度加法
问题描述 输入两个整数a和b,输出这两个整数的和.a和b都不超过100位. 算法描述 由于a和b都比较大,所以不能直接使用语言中的标准数据类型来存储.对于这种问题,一般使用数组来处理. 定义一个数组A ...
- Windows server 2012 添加中文语言包(英文转为中文)(离线)
Windows server 2012 添加中文语言包(英文转为中文)(离线) 相关资料: 公司环境:亚马孙aws虚拟机 英文版Windows2012 中文SQL Server2012安装包,需要安装 ...
- iOS开发系列--Swift语言
概述 Swift是苹果2014年推出的全新的编程语言,它继承了C语言.ObjC的特性,且克服了C语言的兼容性问题.Swift发展过程中不仅保留了ObjC很多语法特性,它也借鉴了多种现代化语言的特点,在 ...
- C语言 · Anagrams问题
问题描述 Anagrams指的是具有如下特性的两个单词:在这两个单词当中,每一个英文字母(不区分大小写)所出现的次数都是相同的.例如,"Unclear"和"Nuclear ...
- C语言 · 字符转对比
问题描述 给定两个仅由大写字母或小写字母组成的字符串(长度介于1到10之间),它们之间的关系是以下4中情况之一: 1:两个字符串长度不等.比如 Beijing 和 Hebei 2:两个字符串不仅长度相 ...
- JAVA语言中的修饰符
JAVA语言中的修饰符 -----------------------------------------------01--------------------------------------- ...
- Atitit 项目语言的选择 java c#.net php??
Atitit 项目语言的选择 java c#.net php?? 1.1. 编程语言与技术,应该使用开放式的目前流行的语言趋势1 1.2. 从个人职业生涯考虑,java优先1 1.3. 从项目实际来 ...
随机推荐
- S_型文法到q_型文法再到LL(1)型文法演进笔记
title: S_型文法到q_型文法再到LL(1)型文法演进笔记 date: 2020-08-23 S_型文法到q_型文法再到LL(1)型文法演进笔记 S_型文法(简单的确定性文法) 每个产生式的右部 ...
- 如何通过 Serverless 轻松识别验证码?
作者 | 江昱 来源 | Serverless 公众号 前言 Serverless 概念自被提出就倍受关注,尤其是近些年来 Serverless 焕发出了前所未有的活力,各领域的工程师都在试图将 Se ...
- javascriptRemke之原型的重要性
前言:JavaScript的原型对象一直是新人学习js的一大重大阻碍,但是原型的知识往往又是面试中常常会被深挖的一个点,为什么会这样呢?本文带你揭秘JavaScript原型的重要性,了解重要性之后再进 ...
- Hibernate的介绍及入门小案例
1.Hibernate的诞生 在以前使用传统的JDBC开发应用系统时,如果是小型应用系统,并不觉得有什么麻烦,但是对于大型应用系统的开发,使用JDBC就会显得力不从心,例如对几十,几百张包含几十个字段 ...
- AT3950 [AGC022E] Median Replace
题目传送门 Description 有一个长度为 \(n\) 的 \(01\) 串,里面有一些还没有确定,我们标记为 ? .可以进行若干次操作,每次操作可以把三个相邻的数替换成它们的中位数.问有多少种 ...
- 随机生成文章的AI(C++)
#include <iostream> #include <cstdlib> #include <ctime> #include <fstream> u ...
- XiaoXin 13Pro-Hackintosh 小新13pro崇尚极简的黑苹果双系统
Lenovo XiaoXin-13-Pro-Hackintosh 关键词:Hackintosh XiaoXin EFI Tutorial Lenovo 以下提及的EFI及其他部分文件见github仓库 ...
- SpringCloud微服务实战——搭建企业级开发框架(六):使用knife4j集成Swagger2接口文档
knife4j是为集成Swagger生成api文档的增强解决方案,前后端Java代码以及前端Ui模块进行分离,在微服务架构下使用更加灵活, 提供专注于Swagger的增强解决方案,不同于只是改善增强前 ...
- no_code团队介绍和bingduoduo项目采访
项目 内容 课程:北航-2020-春-软件工程 博客园班级博客 要求 团队作业-团队介绍和采访 成员简介 name avatar intro PM Dev Test UI/Front-End 伦泽标 ...
- activemq实现队列的独有消费
在我们实际的开发中可能存在这么一种情况,应用程序要向一个队列名为queue的队列中发送3条消息,需要保证这3条消息按顺序消费.必须是第一条消费完,在消费第二条然后是第三条.而我们的程序中可能有时候存在 ...