zoukankan      html  css  js  c++  java
  • hdu 6133 树状数组+分类讨论

    题意:。。比较复杂,就是一个树有点权,一个点的答案是子树的所有点权的前缀和的和(贪心思想转换后的题意),问所有答案。

    首先这是个假题解。。只是提供一个思路。。。数据不强AC了。。。

    思路:标解是个启发式合并。。这里尝试另一种做法(因为不会),平均时间复杂度是nlogn^2。(数据弱。。)考虑合并操作复杂,我们可以分为合并暴力,单个儿子直接得答案两种操作解决问题。(看起来很玄学。。),事实上是这样的,单个儿子的时间复杂度不用解释,肯定是正确的,我们只要维护子树离散化后的个数以及一个sum。对于暴力这部分。。其实也是一拍脑子想出来的。。首先有一个二叉结点我们就要暴力他的子树一次,当他是一个满二叉树的时候,整个排序的过程就类似一个归并树(事实上多一个sort的log),那么其实这个暴力就类似快排了,随机数据下时间复杂度是科学的。。


    代码:

    #include<bits/stdc++.h>
    using namespace std;
    #define MEM(a,b) memset(a,b,sizeof(a))
    #define bug puts("bug");
    #define PB push_back
    #define MP make_pair
    #define X first
    #define Y second
    typedef unsigned long long ll;
    typedef pair<int,int> pii;
    const int maxn=1e5+100;
    const int mod=1e9+7;
    using namespace std;
    ll sum;
    int id[maxn],L[maxn],R[maxn],x,y,n,t,tim,cnt[maxn];
    ll b[maxn],a[maxn],hs[maxn],bit[maxn],ans[maxn],sbit[maxn];
    vector<int> v[maxn];
    void add(int x,int y){
        v[x].PB(y),v[y].PB(x);
    }
    int dfs(int x,int f){
        int ret=1;
        L[x]=tim++;
        b[L[x]]=a[x];
        for(int i=0;i<v[x].size();i++)
            if(v[x][i]!=f)ret+=dfs(v[x][i],x);
        R[x]=tim-1;
        return cnt[x]=ret;
    }
    int lowbit(int x){
        return x&(-x);
    }
    void modify(int x,ll add,ll a[]){
        while(x<maxn){
            a[x]+=add;
            x+=lowbit(x);
        }
    }
    ll get_sum(ll x,ll a[]){
        ll ret=0;
        while(x!=0){
            ret+=a[x];
            x-=lowbit(x);
        }
        return ret;
    }
    void del(int x,int f){
        modify(id[x],-1,bit);
        modify(id[x],-a[x],sbit);
        for(int i=0;i<v[x].size();i++)
            if(v[x][i]!=f)del(v[x][i],x);
    }
    void addx(int x,int f){
        modify(id[x],1,bit);
        modify(id[x],a[x],sbit);
        for(int i=0;i<v[x].size();i++)
            if(v[x][i]!=f)addx(v[x][i],x);
    }
    void sl(int x,int f){
        vector<int> son;
        for(int i=0;i<v[x].size();i++)
            if(v[x][i]!=f)son.PB(v[x][i]);
        int siz=son.size();
        if(siz==0)ans[x]=a[x];
        else if(siz==1){
            sl(son[0],x);
            ans[x]=ans[son[0]]+(get_sum(n+10,bit)-get_sum(id[x],bit))*a[x]+get_sum(id[x],sbit)+a[x];
        }
        else if(siz==2){
            int aa=0,bb=1;
            if(cnt[son[0]]>cnt[son[1]]) swap(aa,bb);
            sl(son[aa],x);
            del(son[aa],x);
            sl(son[bb],x);
            addx(son[aa],x);
            sort(b+L[x],b+R[x]+1);
            sum=0;
            for(int i=L[x];i<=R[x];i++)sum+=b[i],ans[x]+=sum;
        }
        modify(id[x],1,bit);
        modify(id[x],a[x],sbit);
    }
    
    int main(){
        scanf("%d",&t);
        while(t--){
            scanf("%d",&n);
            tim=1;
            MEM(sbit,0),MEM(bit,0);MEM(ans,0);MEM(cnt,0);
            for(int i=0;i<=n+2;i++) v[i].clear();
            for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
            for(int i=1;i<=n;i++) hs[i]=a[i];
            sort(hs+1,hs+n+1);
            int N=unique(hs+1,hs+n+1)-hs;
            for(int i=1;i<=n;i++) id[i]=lower_bound(hs+1,hs+N,a[i])-hs+1;
            for(int i=0;i<n-1;i++) scanf("%d%d",&x,&y),add(x,y);
            dfs(1,-1);
            sl(1,-1);
            for(int i=1;i<=n;i++) printf("%lld ",ans[i]);
            puts("");
        }
    }


  • 相关阅读:
    FineReport——函数
    FineReport——插入行策略
    FineReport——JS二次开发(CSS改变控件样式)
    FineReport——JS二次开发(下拉框)
    汽车系统
    Ubuntu Software setup
    Win 10 乱码 & 字体横过去了
    U-boot 2016.11 代码结构 dra7xx
    samba Ubuntu 16.04
    ftp Ubuntu16.04
  • 原文地址:https://www.cnblogs.com/zhangxianlong/p/10672496.html
Copyright © 2011-2022 走看看