zoukankan      html  css  js  c++  java
  • 完全二叉树+暴力预处理+归并排序——cf894D

    /*
    结点i的左儿子是2i,右儿子是2i+1 
    那么显然这是一棵完全二叉树。
    由于没有很好直接查询的办法,所以先考虑预处理一下这棵树
    根据完全二叉树的性质,sum{size[i]}<=nlogn,所以直接用vector存下结点的所有孩子,自底向上对到子树距离归并排序
    
    这样预处理完后,对于每个询问(A,H),我们只要以A为起点不断向上爬(最多logn次),通过lower_bound来计算贡献 
    */
    #include<bits/stdc++.h>
    #include<vector>
    using namespace std;
    #define N 1000005
    #define ll long long
    
    struct Edge{
        ll to,nxt,w;
    }e[N<<1];
    int head[N],tot;
    void init(){
        memset(head,-1,sizeof head);
        tot=0;
    }
    void add(int u,int v,ll w){
        e[tot].to=v;e[tot].w=w;e[tot].nxt=head[u];head[u]=tot++;
    }
    
    vector<ll>dis[N];
    int n,m;
    
    vector<ll> merge(vector<ll> & fa, vector<ll> & son,ll w){
        vector<ll>res;res.clear();
        int p1=0,p2=0;
        while(1){
            if(fa[p1]<=son[p2]+w){
                res.push_back(fa[p1]);
                ++p1;
            }
            else {
                res.push_back(son[p2]+w);
                ++p2;
            }
            if(p1==fa.size() || p2==son.size())break;
        }
        while(p1<fa.size())
            res.push_back(fa[p1]),p1++;
        while(p2<son.size())
            res.push_back(son[p2]+w),p2++;
        return res;
    }
    void dfs(int u,int pre){
        int son=0;
        for(int i=head[u];i!=-1;i=e[i].nxt){
            int v=e[i].to;
            if(v==pre)continue;
            son++;dfs(v,u);
        }
        dis[u].push_back(0);
        if(son==0)return;
        
        for(int i=head[u];i!=-1;i=e[i].nxt){
            int v=e[i].to;
            if(v==pre)continue;
            dis[u]=merge(dis[u],dis[v],e[i].w);
        }
    }
    vector<ll>sum[N];
    void sumup(){
        for(int i=1;i<=n;i++)sum[i]=dis[i];
        for(int i=1;i<=n;i++){
            for(int j=1;j<sum[i].size();j++)
                sum[i][j]+=sum[i][j-1];
        }
    }
    ll W[N];
    
    ll query(int u,ll H){//在子树u下查询 
        if(H<=0)return 0;
        ll res=0;
        int pos=lower_bound(dis[u].begin(),dis[u].end(),H)-dis[u].begin();
        if(pos==0)return 0;
        pos--;
        res=H*(pos+1)-sum[u][pos];
        return res; 
    }
    
    int main(){
        cin>>n>>m;
        init();
        for(int i=1;i<n;i++){
            ll w;scanf("%lld",&w);
            add((i+1)/2,i+1,w);
            add(i+1,(i+1)/2,w);
            W[i+1]=w;
        }
        dfs(1,1);
        sumup();
        
        while(m--){
            ll A,H;
            scanf("%lld%lld",&A,&H);
            ll sum=query(A,H);
            while(1){
                H-=W[A];
                if(A==1 || H<=0)break;
                int tmp=A;
                A/=2;//A=fa[A]
                sum+=H;
                for(int i=head[A];i!=-1;i=e[i].nxt){
                    int v=e[i].to;
                    if(v==tmp||v<A)continue;
                    sum+=query(v,H-e[i].w);
                }            
            }
            cout<<sum<<'
    ';
        }
    } 
  • 相关阅读:
    第k小元素学习记录
    线段树学习笔记
    数论方面的知识积累
    javascript 例子
    数据绑定以及Container.DataItem的具体分析
    C#委托和事件
    C#中的特性(Attributes)(翻译)
    gridview和repeater中取得行的序号
    理解 Ajax 及其工作原理,构建网站的一种有效方法
    JS数组对象参考
  • 原文地址:https://www.cnblogs.com/zsben991126/p/12299343.html
Copyright © 2011-2022 走看看