2016暑期集训4——数据结构(知识点,模板,简单题题解)

2016暑期集训4——数据结构(知识点,模板,简单题题解)


知识点

  1. 位运算 按位与& 或| 异或^ 取反~ >>右移 相当于除以2 <<左移 相当于乘以2 优先级低 注意运算顺序

  2. RMQ问题

    1. 线段树O(logn),可以修改,不需要预处理。

    2. ST表需要预处理,O(n)预处理,O(1)查询。

    3. ST表是dp思想,用dp[i][j]表示从i开始2^j个连续点的最值,dp[i][j] = max(dp[i][j-1],dp[i+1<<(j-1)][j-1])。把区间下分为两段,求各自最值。

    4. 查询时,如果区间不是2的整幂次,比如查询2~7,长度为6,log6=2,返回max([2~5],[4~7]),中间有重的不影响。

  3. dfs序。大概就是对一棵树dfs,一个节点进去时打个标记,递归子树,出去时打个标记。特点就是一个子树的dfs序(那个标记)是连续的。下面代码。

  4. LCA问题,最近公共祖先。

    1. 搜索算法。记录节点深度,比如要找节点uv的祖先,先让u或v往上走,到deep[u]=deep[v],在一起往上走直到走到一起。还有预处理后再进行多次查询nlogn的算法,白书329页。

    2. 基于RMQ的算法。首先从跟dfs后得到顶点序列vs[i]和对应深度depth[i],对于每个节点,记其在vs中首次出现的下标id[v]。LCA(u,v)=vs[id[u]<=i<=id[v]中令depth最小的i]。白书330

  5. 线段树。线段树练习题集

  6. 扫描线


模板

  • RMQ
int st[MAXN][20];//st表,表示从i开始2^j个连续点的最值
int mm[MAXN];//对数表
void ST(int n)
{
    memset(st,0,sizeof(st));
    memset(mm,0,sizeof(mm));
    mm[0]=-1;
    for(int i=0;i<=n;i++)
    {
        if(i>=1)
        {
            mm[i]=((i&(i-1))==0)?mm[i-1]+1:mm[i-1];
            //求对数表
        }
        st[i][0]=b[i];
    }
    for(int j=1;j<=mm[n];j++)
    {
        for(int i=0;i+(1<<j)-1<n;i++)
        {
            int k=i+(1<<(j-1));
            st[i][j]=max(st[i][j-1],st[k][j-1]);
        }
    }
}
int rmq(int l,int r)
{
    int k=mm[r-l+1];
    return (max(st[l][k],st[r-(1<<k)+1][k]));
}
  • DFS序
//dfs标号记得调试看结果再决定怎么用
typedef struct{
    int in,out;
} Dfs;
Dfs dffs[MAXN];
bool visit[MAXN];
void dfs(int n)
{
    if(!visit[n])
    {
        dffs[n].in=cnt++;
        visit[n]=true;
    }
    else
    {
        return;
    }
    for(int i=head[n];~i;i=G[i].next)//注意这个是链式前向星建图的
    {
        dfs(G[i].to);
    }
    if(visit[n])
    {
        dffs[n].out=(cnt-1);
    }
}
  • LCA问题 单次的搜索算法
vector<int>G[MAXN];//图的邻接表
int root;//根结点编号
int parent[MAXN];//父节点编号 跟的父节点是-1
int depth[MAXN];//节点深度
void dfs(int v,int p,int d)
{
    parent[v]=p;
    depth[v]=d;
    for(int i=0;i<G[v].size();i++)
    {
        if(G[v][i]!=p)
        {
            dfs(G[v][i],v,d+1);
        }
    }
}
void init()
{
    dfs(root,-1,0);
}
//计算LCA
int lca(int u,int v)
{
    //让uv高度相同
    while(depth[u]>depth[v]) u=parent[u];
    while(depth[v]>depth[u]) v=parent[v];
    while(u!=v)
    {
        u=parent[u];
        v=parent[v];
    }
    return u;
}
  • LCA问题 基于RMQ的算法
vector<int>G[MAXN];//图的邻接表
int root;//根结点编号
int vs[MAXN*2+1];//DFS访问顺序
int depth[MAXN*2+1];//节点深度
int id[MAXN];//各顶点在vs中首次出现的下标
void dfs(int v,int p,int d,int &k)
{
    id[v]=k;
    vs[k]=v;
    depth[k++]=d;
    for(int i=0;i<G[v].size();i++)
    {
        if(G[v][i]!=p)
        {
            dfs(G[v][i],v,d+1,k);
            vs[k]=v;
            depth[k++]=d;
        }
    }
}
void init()
{
    int k=0;
    dfs(root,-1,0,k);
    //初始化RMQ
    ???
}
//计算LCA
int lca(int u,int v)
{
    return vs[rmq(min(id[u],id[v]),max(id[u],id[v])+1)];
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值