HDU - 6133 Army Formations(启发式合并+树状数组)

点我看题

题意:给出n个结点,每个结点的信息长度为ai,每个结点发送信息的时间总和为自己发送的时间和加上其子树发完所有的信息,问每个结点发完信息所需要的最小时间。

分析:认真的讲,首先要有一个贪心的思想,尽量让子树中信息较短的先发,这样其上面的结点所消耗的时间会比较少,这样,也就是要计算每个结点排序后的子树和了(当然最后的结果还是要加上自己),可以直接利用树状数组来维护。

c++提交会TLE诶。

参考代码:

#include
#include
#include
#include
#include
#include

using namespace std;
typedef long long ll;
const int maxn = 1e5+5;
int n;//结点个数
int w[maxn];//结点的权值
int value[maxn],id[maxn];//借助val数组和id数组来离散化w,因为w[i]高达1e8
int vsize;//结点不重复值的大小
ll curnum;//当前和
ll cntnum[maxn],cntsum[maxn];//出现的次数的和和值的和
vector e[maxn];//记录边的关系
ll ans[maxn];
int size[maxn];//每个结点的大小
int lson[maxn],rson[maxn];//二叉树左右子树

int GetSize( int rt, int pre)
{
    size[rt] = 1;//初始时只有自己一个结点
    for( int i = 0; i < e[rt].size(); i++)
    {
        if( e[rt][i] != pre)
        {
            if( lson[rt] == -1)
                lson[rt] = e[rt][i];
            else
                rson[rt] = e[rt][i];
            size[rt] += GetSize(e[rt][i],rt);
        }
    }

    //~lson[rt]为真即lson[rt]二进制每位不能全为1,即lson[rt]不能为-1(-1的二进制全1),即lson[rt]不为叶子结点
    //保证左子树小于右子树
    if( ~lson[rt] && ~rson[rt] && size[lson[rt]] > size[rson[rt]])
        swap(lson[rt],rson[rt]);
    return size[rt];
}

inline int lowbit( int x)
{
    return x&(-x);
}

ll Query( ll *arr, int x)
{
    ll ans = 0;
    while( x)
    {
        ans += arr[x];
        x -= lowbit(x);
    }
    return ans;
}

void Update( ll *arr, int x, int val)
{
    if( x == 0)
        return;
    while( x <= vsize)//????
    {
        arr[x] += val;
        x += lowbit(x);
    }
}

void AddNum( int inx)
{
    //所增加的 inx前面的个数乘以当前值加上当前值
    curnum += (Query(cntnum,vsize)-Query(cntnum,inx))*value[inx]+value[inx];
    curnum += Query(cntsum,inx);
    Update(cntnum,inx,1);
    Update(cntsum,inx,value[inx]);
}

void DelNum( int inx)
{
    Update(cntnum,inx,-1);
    Update(cntsum,inx,-value[inx]);
    curnum -= (Query(cntnum,vsize)-Query(cntnum,inx))*value[inx]+value[inx];
    curnum -= Query(cntsum,inx);
}

void clean( int rt)
{
    DelNum(id[rt]);
    if( ~lson[rt])
        clean(lson[rt]);
    if( ~rson[rt])
        clean(rson[rt]);
}

void validate( int rt)
{
    AddNum(id[rt]);
    if( ~lson[rt])
        validate(lson[rt]);
    if( ~rson[rt])
        validate(rson[rt]);
}

void GetAns( int rt)
{
    //左子树为叶子结点
    if( !~lson[rt])
    {
        ans[rt] = w[rt];//得到当前结点的结果
        AddNum(id[rt]);//加上叶子结点对其长辈结点的影响
        return;
    }

    GetAns(lson[rt]);
    //rson[rt] != -1
    if( ~rson[rt])
    {
        clean(lson[rt]);
        GetAns(rson[rt]);
        validate(lson[rt]);
    }
    AddNum(id[rt]);
    ans[rt] = curnum;
}

int main()
{
    ios_base::sync_with_stdio(false);
    int T;
    cin >> T;
    while( T--)
    {
        cin >> n;
        for( int i = 1; i <= n; i++)
        {
            cin >> w[i];
            value[i] = w[i];
        }
        sort(value+1,value+n+1);
        vsize = unique(value+1,value+1+n)-value-1;//得到不重复值的个数

        curnum = 0;
        for( int i = 1; i <= vsize; i++)
            cntnum[i] = cntsum[i] = 0;

        for( int i = 1; i <= n; i++)
        {
            id[i] = lower_bound(value+1,value+vsize,w[i])-value;//离散化,每个id[i]代表w[i]在整个数组中的大小情况
            lson[i] = rson[i] = -1;//初始化每个结点,设其为单独的结点
        }

        for( int i = 1; i <= n; i++)
            e[i].clear();
        int u,v;
        for( int i = 1; i < n; i++)
        {
            cin >> u >> v;
            e[u].push_back(v);
            e[v].push_back(u);
        }

        GetSize(1,0);//GetSize(根节点,父节点)
        GetAns(1);
        for( int i = 1; i <= n; i++)
            cout << ans[i] << " ";
        cout << endl;
    }

    return 0;
}



你可能感兴趣的:(数据结构--树状数组BIT)