codeforces 893F 主席树||线段树合并

题意:有一颗树,树上每个点有给定点权,有m次询问,每次询问点x的所有子树中,与x的距离小于等于k的所有点的点权最小值是多少。题目要求强制在线。

思路:

主席树解法:按照dfs序在树上建立主席树,询问是查询x节点的管辖的那段区间,属于经典操作,问题在于如何控制距离小于等于k,于是我们可以按照点的深度来建主席树,虽然最小值问题不满足前缀相减的性质,但实际上我们并不需要减掉1到dep[x]这段区间,因为x节点dfs序管辖范围的限制,前面的点不会对答案产生影响,所以直接查询1到dep[x]+k这段区间即可。

线段树合并解法:以点的深度为基准来建线段树,对每个点都维护一颗线段树,再进行线段树合并即可。要注意的一点是由于询问的是最小值,而数组的初始值默认为0,所以在线段树合并时要开新点来合并,而不能直接利用已有的点,并且新点对应的最小值为要合并的两个点的最小值,而不能直接取左右儿子的最小值。

以前一直觉得线段树合并和主席树非常类似,但是又说不出个所以然,这道题很好的展现了线段树合并与主席树的异同点。

 

主席树代码:

#include
using namespace std;
const int maxn=1e5+5;
const int inf=0x3f3f3f3f;
int a[maxn];
vector g[maxn];
int root[maxn];
int dep[maxn];
int pl[maxn],pr[maxn];
int tree[maxn*40],ls[maxn*40],rs[maxn*40];
int cnt;
int tot;
void pushup(int k)
{
    tree[k]=min(tree[ls[k]],tree[rs[k]]);
}
void build(int &x,int l,int r)
{
    x=++cnt;
    tree[x]=inf;
    if(l==r) return ;
    int mid=(l+r)/2;
    build(ls[x],l,mid);
    build(rs[x],mid+1,r);
}
void insert(int &x,int pre,int l,int r,int pos,int c)
{
    if(!x) x=++cnt;
    if(l==r)
    {
        tree[x]=c;
        return ;
    }
    int mid=(l+r)/2;
    if(pos<=mid) insert(ls[x],ls[pre],l,mid,pos,c),rs[x]=rs[pre];
    else insert(rs[x],rs[pre],mid+1,r,pos,c),ls[x]=ls[pre];
    pushup(x);
}
int query(int L,int R,int l,int r,int x)
{
    if(L<=l&&r<=R) return tree[x];
    int mid=(l+r)/2;
    int mmin=inf;
    if(L<=mid) mmin=min(mmin,query(L,R,l,mid,ls[x]));
    if(R>mid) mmin=min(mmin,query(L,R,mid+1,r,rs[x]));
    return mmin;
}
void dfs(int x,int pre)
{
    dep[x]=dep[pre]+1;
    pl[x]=++tot;
    for(int i=0;i q;
    q.push(x);
    int pre=0;
    while(!q.empty())
    {
        int now=q.front();q.pop();
        vis[now]=1;
        insert(root[pre+1],root[pre],1,n,pl[now],a[now]);
        mp[dep[now]]=++pre;
        for(int i=0;i

 

线段树合并代码:

#include
using namespace std;
const int maxn=1e5+5;
const int inf=0x3f3f3f3f;
int a[maxn];
vector g[maxn];
int root[maxn];
int dep[maxn];
int tree[maxn*40],ls[maxn*40],rs[maxn*40];
int cnt;
void pushup(int k)
{
    tree[k]=min(tree[ls[k]],tree[rs[k]]);
}
void update(int p,int c,int l,int r,int &x)
{
    if(!x)
        x=++cnt;
    tree[x]=c;
    if(l==r)
    {
        return ;
    }
    int mid=(l+r)/2;
    if(p<=mid) update(p,c,l,mid,ls[x]);
    else update(p,c,mid+1,r,rs[x]);
}
int merge(int x,int y)
{
    if(!x) return y;
    if(!y) return x;
    int now=++cnt;
    ls[now]=merge(ls[x],ls[y]);
    rs[now]=merge(rs[x],rs[y]);
    tree[now]=min(tree[x],tree[y]);
    return now;
}
void dfs1(int x,int pre)
{
    dep[x]=dep[pre]+1;
    for(int i=0;imid)
        mmin=min(mmin,query(L,R,mid+1,r,rs[k]));
    return mmin;
}
int main()
{
    int n,r;
    scanf("%d%d",&n,&r);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    for(int i=1;i

 

你可能感兴趣的:(acm)