[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. 从项目实际来 ...
随机推荐
- openssl 生成证书上 grpc 报 legacy Common Name field, use SANs or temporarily enable Common Name matching with GODEBUG=x509ignoreCN=0
最近用传统的方式 生成的证书上用golang 1.15. 版本 报 grpc 上面 ➜ ~ go version go version go1.15.3 darwin/amd64 上面调用的时候报错了 ...
- Hibernate的介绍及入门小案例
1.Hibernate的诞生 在以前使用传统的JDBC开发应用系统时,如果是小型应用系统,并不觉得有什么麻烦,但是对于大型应用系统的开发,使用JDBC就会显得力不从心,例如对几十,几百张包含几十个字段 ...
- 阿里P8面试官:如何设计一个扛住千万级并发的架构?
大家先思考一个问题,这也是在面试过程中经常遇到的问题. 如果你们公司现在的产品能够支持10W用户访问,你们老板突然和你说,融到钱了,会大量投放广告,预计在1个月后用户量会达到1000W,如果这个任务交 ...
- find+xargs+sed批量替换
写代码时经常遇到要把 .c 和 .h的文件中的某些内容全部替换的情况,用sourceinsight 进行全局的查找是一个方法,但是sourceinsight只能替换一个文件中的字符串,不能同时替换多 ...
- 【原创】浅谈指针(五)const和指针
前言 过了几个月再次更新.最近时间也不多了,快要期中考试了,暂且先少写一点吧. 本文仅在博客园发布,如在其他平台发现均为盗取,请自觉支持正版. 练习题 我们先来看几道题目.如果这几道题都不会的话,就先 ...
- Noip模拟77 2021.10.15
T1 最大或 $T1$因为没有开$1ll$右移给炸掉了,调了一年不知道为啥,最后实在不懂了 换成$pow$就过掉了,但是考场上这题耽误了太多时间,后面的题也就没办法好好打了.... 以后一定要注意右移 ...
- Noip模拟58 2021.9.21(中秋祭&&换机房祭)
第一次在学校过中秋节,给家里人视频电话,感觉快回家了很开心, 然后还吃了汉堡喝饮料非常爽,颓废了一会儿还换了新机房,$Linux2.0$非常dei,少爷机也非常快, 发现好像测评机又成了老爷机,这就是 ...
- QEvent
QEvent类是所有事件类的基类,每一个对象都包含事件参数.Qt的主事件循环(QCoreApplication::exec())从事件队列中接收本地窗口系统的事件,并将它们翻译成QEvent,将这些事 ...
- 洛谷 P4555 [国家集训队]最长双回文串
链接: P4555 题意: 在字符串 \(S\) 中找出两个相邻非空回文串,并使它们长度之和最大. 分析: 直接使用马拉车算法求出每个点扩展的回文串.如果枚举两个回文串显然会超时,我们考虑切割一个长串 ...
- Vue:Vue的介绍以及组件剖析
介绍 现在,随着基于JavaScript的单页应用程序(SPA)和服务器端渲染(SSR)的兴起,可以用JavaScript编写整个前端应用程序,并整洁地管理和维护该应用程序的前端代码.诸如Angula ...