HDU 6133 Army Formations

HDU 6133 Army Formations

dsu on tree

題意

給你一棵n個節點的二叉樹,每個節點有一個提交任務的時間,每個節點總的提交任務的罰時爲:提交這個節點和其子樹所有的任務,每個任務提交時間的總和爲該點的罰時。求每個節點提交完所有任務的最小罰時

思路

樹上啓發式合併。

考慮有這樣一個數據結構, 可以動態往一個多重集裏面添加數字, 刪除數字, 並查詢多重集中元素的sumofsum.
這個非常簡單, 用樹狀數組就好了.

然後我們考慮這樣一個啓發式過程. 定義一個dfs(root), root表示當前子樹的根, 用left_son, right_son表示兩個兒子, 且左子樹的大小比右子樹小.

def tree_remove(root):
    for x in tree(root): 
        remove_from_multiset(x)

def tree_add(root): 
    for x in tree(root): 
        add_into_multiset(x)

def dfs(root): 
    dfs(left_son) 
    tree_remove(left_son) 
    dfs(right_son) 
    tree_add(left_son) 
    add_into_multiset(root) 
    f[root] = ask_sumofsum()

其中 add_into_multiset, remove_from_multiset, ask_sumofsum爲上面說到的數據結構支持的操作: 添加數字, 刪除數字, 查詢sumofsum.

而tree(root)表示以root爲根的子樹中的節點. tree_remove(root)和tree_add(root)其實就是遍歷以root爲根的子樹中的節點, 並把他們加到多重集或者從多重集中刪除.

複雜度就是, 每個節點被 remove_from_multiset 的次數是 O(logn) 的, 因爲每次被 remove 都是因爲這個節點處於一個較小的子樹中. 這樣 remove_from_multiset 和 add_into_multiset 的執行次數都是 O(logn) , 然後考慮樹狀數組的複雜度, 總複雜度就是 O(nlog2n)

代碼


#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define M(a,b) memset(a,b,sizeof(a))
using namespace std;
const int MAXN=100007;
const int oo=0x3f3f3f3f;
typedef long long LL;

int l[MAXN], r[MAXN], sz[MAXN];
struct Edge
{
    int to, ne;
}e[2*MAXN];
int head[MAXN], edgenum;
void addedge(int u, int v)
{
    e[edgenum].to=v, e[edgenum].ne=head[u];head[u]=edgenum++;
    e[edgenum].to=u, e[edgenum].ne=head[v];head[v]=edgenum++;
}
void dfs1(int u, int fa)//???????sz
{
    sz[u]=1;
    for(int i=head[u];~i;i=e[i].ne)
    {
        int to=e[i].to;
        if(to==fa) continue;
        dfs1(to, u);
        sz[u]+=sz[to];
        if(r[u]==0) r[u]=to;
        else if(sz[to]>sz[r[u]])
            l[u]=r[u], r[u]=to;
        else l[u]=to;
    }
}
LL sum[MAXN<<2], num[MAXN<<2];
int lowbit(int x) { return x&(-x); }
void update(LL f[], int pos, int val, int tot)
{
    while(pos<=tot)
    {
        f[pos]+=val;
        pos+=lowbit(pos);
    }
}
LL query(LL f[], int pos)
{
    LL ans=0;
    while(pos)
    {
        ans+=f[pos];
        pos-=lowbit(pos);
    }
    return ans;
}

int v[MAXN], ha[MAXN], hav[MAXN];
LL vsum[MAXN];
LL res=0;
void tree_add(int rt, int n)
{
    if(rt==0) return;
    res+=(query(num, n)-query(num, ha[rt]))*v[rt];
    res+=query(sum, ha[rt])+v[rt];
    update(num, ha[rt], 1, n);
    update(sum, ha[rt], v[rt], n);
    tree_add(l[rt], n), tree_add(r[rt], n);
}
void tree_rem(int rt, int n)
{
    if(rt==0) return;
    res-=(query(num, n)-query(num, ha[rt]))*v[rt];
    res-=query(sum, ha[rt]);
    update(num, ha[rt], -1, n);
    update(sum, ha[rt], -v[rt], n);
    tree_rem(l[rt], n), tree_rem(r[rt], n);
}
void dfs2(int n, int u)
{
    if(u==0) return;
    if(l[u]!=0) dfs2(n, l[u]);
    if(l[u]!=0) tree_rem(l[u], n);
    if(r[u]!=0) dfs2(n, r[u]);
    if(l[u]!=0) tree_add(l[u], n);


    res+=(query(num, n)-query(num, ha[u]))*v[u];
    res+=query(sum, ha[u])+v[u];
    update(num, ha[u], 1, n);
    update(sum, ha[u], v[u], n);
    vsum[u]=res;
}
int main()
{
    int T;scanf("%d", &T);
    while(T--)
    {
        M(l, 0), M(r, 0), M(sz, 0);
        M(head, -1);edgenum=1;
        M(ha, 0), M(v, 0), M(vsum, 0);

        int n;scanf("%d", &n);
        for(int i=1;i<=n;i++)
        {
            scanf("%d", &v[i]);
            hav[i]=v[i];
        }
        sort(hav+1, hav+1+n);
        int han=unique(hav+1, hav+n+1)-hav-1;
        for(int i=1;i<=n;i++)
            ha[i]=lower_bound(hav+1, hav+1+han, v[i])-hav;
        for(int i=1;i<n;i++)
        {
            int u, v;scanf("%d%d", &u, &v);
            addedge(u, v);
        }
        dfs1(1, 0);
        M(num, 0), M(sum, 0);res=0;
        dfs2(han, 1);
        for(int i=1;i<=n;i++) printf("%lld ", vsum[i]);

        printf("\n");

    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章