zoukankan      html  css  js  c++  java
  • 洛谷P3605 [USACO17JAN]Promotion Counting——线段树合并

     

    线段树合并裸题,其实这道题就可以看作每一个点的子树中比它的点权大的值的个数。看这道题的值域范围,知道要用动态开点的线段树,然后我们可以将p数组离散化,每一个点都建一棵对应的值域线段树。最后从根节点开始遍历,回溯时将有上司和下属关系的点合并即可。

    而关键是合并操作:

    其实还是很好理解的,我的代码没有新开一个节点,就相当于把y合并到x上,从根节点开始,向下递归更新即可,还是比较暴力的。

    完整代码如下:

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=3e6+7;
    struct node{
        int nxt;
        int to;
    }edge[maxn*2];
    int lc[maxn],rc[maxn];
    int T;
    int a[maxn],p[maxn];
    int root[maxn];
    struct seg{
        int val;
    }tree[maxn*3];
    int head[maxn],tot;
    int n;
    int x;
    int neww;
    int ans[maxn];
    void add(int x,int y){
        edge[++tot].nxt=head[x];
        edge[tot].to=y;
        head[x]=tot;
    }
    void build(int &node,int l,int r,int x){
        if(!node) node=++T;
        if(l==r){
            tree[node].val++;
            return;
        } 
        int mid=(l+r)>>1;
        if(x<=mid){
            build(lc[node],l,mid,x);
        } 
        else{
            build(rc[node],mid+1,r,x);
        }
        tree[node].val=tree[lc[node]].val+tree[rc[node]].val; 
    }
    void merge(int &x,int y){
        if(!x||!y){
            x=x+y;
            return;
        }
        tree[x].val=tree[x].val+tree[y].val;
        merge(lc[x],lc[y]);
        merge(rc[x],rc[y]);
    }
    int query(int node,int l,int r,int v){
        if(l==r) return 0;
        int mid=(l+r)>>1;
        if(v<=mid) return query(lc[node],l,mid,v)+tree[rc[node]].val;
        else return query(rc[node],mid+1,r,v); 
    }
    void dfs(int x){
        for(int i=head[x];i;i=edge[i].nxt){
            int v=edge[i].to;
            dfs(v);
            merge(root[x],root[v]);//回溯时暴力合并 
        }
        ans[x]=query(root[x],1,neww,p[x]);
    }
    int main(){
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            scanf("%d",&p[i]);
            a[i]=p[i];
        } 
        std::sort(a+1,a+1+n);
        neww=unique(a+1,a+1+n)-a-1;
        for(int i=2;i<=n;i++){
            scanf("%d",&x);
            add(x,i);
        }
        for(int i=1;i<=n;i++){
            p[i]=lower_bound(a+1,a+1+neww,p[i])-a;//离散化 
            build(root[i],1,neww,p[i]);
        }
        dfs(1);
        for(int i=1;i<=n;i++){
            printf("%d
    ",ans[i]);
        }
        return 0;
    } 
    View Code
  • 相关阅读:
    删除链表的倒数第N个节点
    SVN快速入门(TSVN)
    C# HttpWebRequest提交数据方式浅析
    简单的3个SQL视图搞定所有SqlServer数据库字典
    简单统计SQLSERVER用户数据表大小(包括记录总数和空间占用情况)
    详细讲解Android对自己的应用代码进行混淆加密防止反编译
    PHP之网络编程
    PHP之ThinkPHP模板标签操作
    PHP之ThinkPHP数据操作CURD
    关于数组的取极值和排序
  • 原文地址:https://www.cnblogs.com/LJB666/p/11234726.html
Copyright © 2011-2022 走看看