高级树与动态统计问题

发布 2021-04-27 11:08:28 阅读 5907

一、赢者树。

为决定一场比赛的赢家,假设每个选手有一得分且赢者取决于对两选手得分的比较。在最小赢者树(min winner tree)中,得分小的选手获胜;同理,在最大赢者树(max winner tree)中,得分大的选手获胜。有时,也可用左孩子对应的选手代表赢家节点。

图 10-2a 给出含8名选手的最小赢者树,而图10-2b 给出含5名选手的最大赢者树。每个外部节点之下的数字表示选手得分。

定义 [赢者树] 对于n 名选手,赢者树是一棵含n 个叶子节点,n-1个非叶子节点的完全二叉树,其中每个内部节点记录了相应赛局的赢家。

操作一:初始化一颗赢者树。

template

void wtree_init(t *wt,t *a,int n)

int i;

for(i=0;i for(i=n-1;i>0;i--)wt[i]=min(a[i*2],a[i*2+1]);

操作二:修改一个叶结点的值。

template

void wtree_update(t *wt,t v,int s)

s/=2;while(max(wt[s*2],wt[s*2+1])!wt[s]&&s>1)

操作三:求解子区间的“赢者”

template

t wtree_cal(t *wt,int fr,int re)

int res=inf;

while(fr

return res;

template

t wtree_cal_rec(t *wt,int fr,int re)

if(fr==re) return wt[fr];

if(fr%2==1) return min(wt[fr],wtree_cal_rec(wt,fr+1,re));

if(re%2==1) return min(wt[re],wtree_cal_rec(wt,fr,re-1));

return min(wtree_cal_rec(fr/2,re/2));

例1-1 [排序] 可用一个最小赢者树在 (nl o gn)时间内对n 个元素进行排序。

首先,用n 个元素代表n 名选手对赢者树进行初始化。利用元素的值来决定每场比赛的结果,最后的赢家为具有最小值的元素,然后将该选手(元素)的值改为最大值 (如∞),使它赢不了其他任何选手。

在此基础上,重构该赢者树,所得到的最终赢家为该排序序列中的下一个元素。以此类推,可以完成n 个元素的排序,时耗为 (n)。每次改变竞赛赢家的值并重构赢者树的时耗为 ( l o gn),这个过程共需执行n- 1次,因此整个排序过程所需要的时间为 (nl o gn)。

例1-2 [rmq问题] 给定长度不超过100000的整数序列,对这个序列进行不超过100000次操作,操作有两种类型:,将第i个元素的值改成v;,询问区间[i,j]上的最大值。

要求回答所有询问。

例1-3 将上例中的第二种操作改为询问区间[i,j]上的和值。

例1-4 给一张平面星图,计算每颗星星左下方的星星总数。

一棵含有n个叶结点的赢者树t[n]对应于一个含有n个元素的序列a[n],它的节点上存储了a[n]的子序列的统计信息。他使得对a[n]的单点更新和任意子区间的统计均可以再logn时间内完成。

二、线段树。

定义 [线段树] 一棵二叉树,记为t (a,b),参数a,b表示该节点表示区间[a,b]。区间的长度b-a记为l。递归定义t[a,b]:

若l>1 :[a, (a+b)/2]为 t的左儿子 ,a+b)/2,b]为t的右儿子。

若l=1 :t为一个叶子节点。

表示区间[1, 10]的线段树表示如下:

定理:线段树把区间上的任意一条线段都分成不超过 2logl条线段。

这个结论为线段树能在 o(logl)的时间内完成一条线段的插入、删除、计算等工作,提供了理论依据。

struct stnode

int fr,re;

统计与操作信息。

线段树与赢者树一样对应于一个序列,相比于赢者树它支持对序列子区间实施整体变更。它主要有以下三种操作:

操作一:创建一棵线段树。

void build(stnode *a,int fr,int re,int s)

a[s].fr=fr;

a[s].re=re;

if(re-fr>1)

操作二:更新一个子区间。

void insert( *a,int fr,int re,int s,//

int mid;

if(fr==a[s].fr&&re==a[s].re)

mid=(a[s].fr+a[s].re)/2;

if(fr

else if(re<=mid) insert(a,fr,re,s*2,v);

else insert(a,fr,re,s*2+1,v);

操作三:求解一个子区间。

例2-1 给定长度不超过100000的整数序列,对这个序列进行不超过100000次操作,操作有两种类型:,将区间[i,j]上的每个元素的值增加v;,询问区间[i,j]上的最大值。

要求回答所有询问。

template

struct stnode

int fr,re;

int v;

tstat st;

template

void build(stnode *a,int fr,int re,int s)

a[s].fr=fr;

a[s].re=re;

a[s].v=0;

(a[s].st).init(fr,re);

if(re-fr>1)

template

void insert(stnode *a,int fr,int re,int s,int v)

int mid;

if(fr==a[s].fr&&re==a[s].re)

return;

mid=(a[s].fr+a[s].re)/2;

if(fr

else if(re<=mid) insert(a,fr,re,s*2,v);

else insert(a,fr,re,s*2+1,v);

(a[s].st).unite(a[s*2].st,a[s*2+1].st);

(a[s].st).update(a[s].v);

template

tstat calculate(stnode *a,int fr,int re,int s)

int mid;

tstat tmp;

if(fr==a[s].fr&&re==a[s].re) return a[s].st;

mid=(a[s].fr+a[s].re)/2;

if(fr else if(re<=mid) tmp=calculate(a,fr,re,s*2);

else tmp=calculate(a,fr,re,s*2+1);

return tmp;

class stat

public:

bool m;

void init(int fr,int re)

bool update(int v)

void unite(stat a,stat b)

例2-2 球矩形并的面积和体积。

class stat

public:

int s,l;

void init(int fr,int re)

bool update(int v)

return false;

void unite(stat a,stat b)

class stat

public:

bool bfr,bre;

int n;

void init(int fr,int re)

bool update(int v)

return false;

void unite(stat a,stat b)

bfr=bre=

3概率与统计问题作业

高考中概率与统计问题的热点题型。1.2016 全国 卷 某险种的基本保费为a 单位 元 继续购买该险种的投保人称为续保人,续保人本年度的保费与其上年度出险次数的关联如下 设该险种一续保人一年内出险次数与相应概率如下 1 求一续保人本年度的保费高于基本保费的概率 2 若一续保人本年度的保费高于基本保费...

高级统计实务与案例分析大纲

高级统计实务与案例分析 考试大纲。一 考试目的。遵循突出能力考核的原则,以统计工作流程为主线,全面考察统计专业技术人员运用数据信息,分析 判断 处理统计业务和解决统计工作实际问题的综合能力。二 考试基本要求。一 统计调查设计。1.准确把握 企事业单位和社会公众等统计用户需求,熟悉国家统计指标体系和分...

高级统计实务与案例分析试卷 2019

二 一六年高级统计师资格考评结合考试。1 本试卷有两部分,共8道题,满分150分。其中第一部分为必答题,共6道题,满分130分 第二部分为选答题,要求选答1道题,若多答,评卷时只对前1道答题打分,满分20分。2 在你拿到试卷的同时将得到一份专用答题卡,所有试题务必在专用答题卡上作答,在试卷或草稿纸上...