[51nod1709]复杂度分析

  给出一棵n个点的树(以1号点为根),定义dep[i]为点i到根路径上点的个数。众所周知,树上最近公共祖先问题可以用倍增算法解决。现在我们需要算出这个算法精确的复杂度。我们定义计算点i和点j最近公共组先的精确复杂度为bit[dep[i]-dep[lca(i,j)]]+bit[dep[j]-dep[lca(i,j)]](bit[i]表示i在二进制表示下有多少个1,lca(i,j)表示点i和点j的最近公共祖先)。为了计算平均所需的复杂度为多少,请你帮忙计算任意两点计算最近公共组先所需复杂度的总和。
即计算 sum{ bit[dep[i]-dep[lca(i,j)]]+bit[dep[j]-dep[lca(i,j)]] } ,1<=i<n,i+1<=j<=n;
 Input
  第一行一个数n表示点数(1<=n<=100,000)
  接下来n-1行每行两个数x,y表示一条边(1<=x,y<=n)
 Output
  一个数表示答案

  抱sxt大腿系列。。大概思路就是统计每个点往上跳每一步对答案的贡献。。先倍增预处理出每个点的那些父亲还有到父亲的那条边。

  大概就是统计一下能从子树里跳到当前点的节点数,那些点就能当前父亲其他儿子里能跳到父亲的节点一起贡献。。。

  当然不能每次直接跑。。就把查询都存到到父亲的边里面,最后再dfs一遍统计。

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<queue>
 6 #include<cmath>
 7 #include<cstdlib>
 8 #include<bitset>
 9 //#include<ctime>
10 #define ll long long
11 #define ull unsigned long long
12 #define ui unsigned int
13 #define d double
14 //#define ld long double
15 using namespace std;
16 const int maxn=100233,mxnode=maxn<<1;
17 struct zs{int too,pre;}e[maxn<<1];int tot,last[maxn];
18 int fa[maxn][18],fae[maxn][18],num[maxn],pos[maxn],TIM,sz[maxn];
19 ll sum[maxn],sume[maxn<<1];
20 int i,j,k,n,m;
21 ll ans;
22
23 int ra,fh;char rx;
24 inline int read(){
25     rx=getchar(),ra=0,fh=1;
26     while((rx<‘0‘||rx>‘9‘)&&rx!=‘-‘)rx=getchar();
27     if(rx==‘-‘)fh=-1,rx=getchar();
28     while(rx>=‘0‘&&rx<=‘9‘)ra=ra*10+rx-48,rx=getchar();return ra*fh;
29 }
30
31 inline void dfs(int x){
32     register int i,to;pos[++TIM]=x,sz[x]=num[x]=1;
33     for(i=1;i<18;i++)fa[x][i]=fa[fa[x][i-1]][i-1],fae[x][i]=fae[fa[x][i-1]][i-1];
34     for(i=last[x];i;i=e[i].pre)if((to=e[i].too)!=fa[x][0])
35         fa[to][0]=x,fae[to][0]=i,dfs(to),sz[x]+=sz[to];
36 }
37 inline void DFS(int x){
38     register int i,to;
39     for(i=last[x];i;i=e[i].pre)if((to=e[i].too)!=fa[x][0])
40         ans+=1ll*sume[i]*(sz[x]-sz[to]),DFS(to);
41 }
42 inline void insert(int a,int b){
43     e[++tot].too=b,e[tot].pre=last[a],last[a]=tot,
44     e[++tot].too=a,e[tot].pre=last[b],last[b]=tot;
45 }
46 int main(){
47     n=read();register int i,j;
48     for(i=1;i<n;i++)insert(read(),read());
49     dfs(1);
50     int f;
51     for(j=0;j<18;j++)for(i=1;i<=n;i++)if((f=fa[k=pos[i]][j]))
52         num[f]+=num[k],sum[f]+=num[k]+sum[k],sume[fae[k][j]]+=num[k]+sum[k];
53     DFS(1),printf("%lld\n",ans);
54 }

时间: 2024-10-06 21:48:56

[51nod1709]复杂度分析的相关文章

51nod1709复杂度分析

题解: 注意到,如果第j位有贡献,那么从i往上跳2^j,然后不能再跳超过2^j. 因此可以考虑倍增. 代码: #include<bits/stdc++.h> typedef long long ll; using namespace std; const int N=100233,M=N<<1; struct zs{int too,pre;}e[N<<1]; int tot,last[N],fa[N][18],fae[N][18],num[N],pos[N],TIM,s

51nod 1709 复杂度分析

51nod 1709 复杂度分析 考虑定义 $ F(x) $ 为 \(x\) 为根的子树所有点与 $ x $ 的深度差(其实就是 $ x $ 到每个子树内点的距离)的 1 的个数和. 注意,$ F(x) $ 的值不是答案,但是只需要一点树形dp的基础内容就可以变成要求的答案. 对于一个点 $ u $ , 考虑它的一个儿子 $ v $ , 我们此时已经计算出了 $ F( v ) $ 的值那么怎么统计 $ v $中所有点对于 $ u $ 的贡献呢?首先考虑 $ F(v) $ 的变化,由于当前的点 $

算法录 之 复杂度分析。

一个算法的复杂度可以说也就是一个算法的效率,一般来说分为时间复杂度和空间复杂度... 注意接下来说的均是比较YY的,适用与ACM等不需严格分析只需要大致范围的地方,至于严格的算法复杂度分析的那些数学证明,主定理什么的在<算法导论>这本书上有十分详细的讲解,网上应该也会有人写过,这里就不多说了(其实,是我不会而已o(╯□╰)o...). — 到底啥是复杂度呢?先来个栗子. 小明有10个苹果,有一天他饿了,然后准备吃掉一个苹果,但是小明有中二病,他要吃里面重量最大的那个,于是...他需要一个找到那

相似度分析的地址

相似度分析的,其中的分词可以采用HanLP即可: http://www.open-open.com/lib/view/open1421978002609.htm

Python 文本相似度分析

环境 Anaconda3 Python 3.6, Window 64bit 目的 利用 jieba 进行分词,关键词提取 利用gensim下面的corpora,models,similarities 进行语料库建立,模型tfidf算法,稀疏矩阵相似度分析 代码 # -*- coding: utf-8 -*- import jieba from gensim import corpora, models, similarities from collections import defaultdi

斐波那契数与二分法的递归与非递归算法及其复杂度分析

1. 什么是斐波那契数? 这里我借用百度百科上的解释:斐波那契数,亦称之为斐波那契数列(意大利语: Successione di Fibonacci),又称黄金分割数列.费波那西数列.费波拿契数.费氏数列,指的是这样一个数列:0.1.1.2.3.5.8.13.21.--在数学上,斐波纳契数列以如下被以递归的方法定义:F0=0,F1=1,Fn=Fn-1+Fn-2(n>=2,n∈N*),用文字来说,就是斐波那契数列列由 0 和 1 开始,之后的斐波那契数列系数就由之前的两数相加.特别指出:0不是第一

递归算法复杂度分析方法

递归算法的复杂度分析方法. a.分析出复杂度公式(关于n的规模) b.求解这个公式 1.齐次 例如求fabonaci的第n项,f(n) = f(n-1)+f(n-2) => f(n)-f(n-1)-f(n-2)=0 =>特征方程:x^2-x-1=0 => x1,x2 => f(n)=a*x1n + b*x2n 2.master method T(n) = aT(n/b) + f(n) 3.采用分析树的方式 举个例子 f(n) = 2*f(n-1) + 1 1 1 ---------

杨辉三角(Pascal Triangle)的几种C语言实现及其复杂度分析

说明 本文给出杨辉三角的几种C语言实现,并简要分析典型方法的复杂度. 本文假定读者具备二项式定理.排列组合.求和等方面的数学知识. 一  基本概念 杨辉三角,又称贾宪三角.帕斯卡三角,是二项式系数在三角形中的一种几何排列.此处引用维基百科上的一张动态图以直观说明(原文链接http://zh.wikipedia.org/wiki/杨辉三角): 从上图可看出杨辉三角的几个显著特征: 1. 每行数值左右对称,且均为正整数. 2. 行数递增时,列数亦递增. 3. 除斜边上的1外,其余数值均等于其肩部两数

算法9-4:最大流算法复杂度分析

前面一节介绍了Ford-Fulkerson算法.那么这个算法是否一定能够在有限步骤内结束?要多少步骤呢? 这个问题的答案是,该算法确实能够在有限步骤之内结束,但是至于需要多少步骤,就要仔细分析. 为了分析问题,需要假定图中所有边的容量都是整数.但是有个严重的问题,比如下图中,如果使用Ford-Fulkerson算法,需要迭代200次才能结束. 首先将所有边的容量都初始化为0. 第一次迭代和第二次迭代之后,两条边各增加了1. 到最后200次迭代之后整个算法才结束. 这还不算最坏的情况.因为整数最多