@codechef - TREEPATH@ Decompose the Tree


@description@

Given an unrooted tree on each node to write an integer.
Your task is to count how many ways these trees can be broken down into several paths so that each node belongs to exactly one path, and the sum of the numbers of nodes on each path and non-negative.

Input format
input data of the first line contains an integer T, denotes the number of data sets.
The next set of data is T. The first line of each data contains an integer N, the representative number of nodes in the tree.
The next line contains N integers, separated by spaces, represents a number of write on each node.
Next N -1 rows, each row comprising two integers Xj and Yj, that there is an edge between the representative number Xj and Yj directly connected nodes.

Output Format
For each test, an output line, comprising an integer, the results of ^ 9 +7 modulo obtained is the number of tree decomposition scheme 10.

Data range and the subtasks
• ^. 1. 5 ≤ T ≤ 10
• ≤ Xj of. 1, Yj ≤ N

Sample data
input
. 1 4
. 1. 5 10 -1
. 1 2
. 1. 3
2 4
Output
4

Sample explain
a total of four kinds of decomposition methods:
• a path is the entire tree, and which is + 10. 5 + +. 1 (-1) = 15;
• a path comprising nodes 2 and 4, the sum is 10 + ( -1) = 9; other path comprising the nodes 1 and 3, and =. 5. 6 + 1;
• a path comprising nodes 1, 2 and 4, the sum is 10 + 1 + (- 1) = 10; the other path contains a node 3, and it is. 5;
• a first path comprising nodes 2 and 4, the sum is 10 + (-1) = 9; the second path comprises a node 1, which is 1; Article path contains a node 3, and which is 3.

@solution@

First, it is conceivable that a simple dp: definition of dp [x] an exploded x is the number of legal program sub-tree roots.
To enumerate a lca when x is zero transfer chain, dp value chain of branches of all expenditures go up to ride.
Do this way is O (n ^ 2), consider optimizing.

We consider the use of heuristics can merge + tree to optimize our balance enumerate chain process.
Consider processed baryon lepton tree inheritance tree, we maintain baryon son climbed up the tree each dp value chain of a product and the weight of the current point and the branches.
Dp value of the product of each coupled to the chain weights and val current point, multiplied by the number of the light programs subtree by playing tag.

Then consider addressing leptons tree. A first end of the light chain statistical sub-tree, and the other end to maintain balance in the case in the current tree.
This embodiment can maintain a number of subtrees of the tree and by balancing the weight split into + <k and> = k of the two balanced tree, and take> = k balanced tree to get answers.
Then put the tree lepton tree chain thrown into the balance of all of the tree.

Finally, the current root is added, and then remember to remove the weights in a balanced tree and> = 0 the number of program chains (i.e., chains endpoint is the current point).

Looks perfect, but there is one problem: in case dp value of 0 (no program itself may or may program a few too many mod 10 ^ 9 + 7 = 0 ), the inverse element does not exist.
Of course, a lot of solutions, but I chose the simplest (most sb) solution: to determine how much it has a value of 0 dp son.
If more than two apparently on the total number of schemes to 0, or Category talk a lot, then WA to suspect life. . .

@accepted code@

#include<cstdio>
#include<queue>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
const int MAXN = 100000;
const int MOD = int(1E9) + 7;
inline int add(int a, int b) {return (a + b)%MOD;}
inline int mul(int a, int b) {return 1LL*a*b%MOD;}
int pow_mod(int b, int p) {
    int ret = 1;
    while( p ) {
        if( p & 1 ) ret = 1LL*ret*b%MOD;
        b = 1LL*b*b%MOD;
        p >>= 1;
    }
    return ret;
}
struct edge{
    edge *nxt; int to;
}edges[2*MAXN + 5], *adj[MAXN + 5], *ecnt=&edges[0];
void addedge(int u, int v) {
    edge *p = (++ecnt);
    p->to = v, p->nxt = adj[u], adj[u] = p;
    p = (++ecnt);
    p->to = u, p->nxt = adj[v], adj[v] = p;
}
int siz[MAXN + 5], hvy[MAXN + 5];
void dfs1(int x, int f) {
    siz[x] = 1, hvy[x] = 0;
    for(edge *p=adj[x];p;p=p->nxt) {
        if( p->to == f ) continue;
        dfs1(p->to, x);
        siz[x] += siz[p->to];
        if( siz[p->to] > siz[hvy[x]] )
            hvy[x] = p->to;
    }
}
struct Treap{
    struct node{
        node *ch[2];
        int key, cnt, sum;
        int tg1, tg2;
        unsigned int pri;
    }pl[MAXN + 5], *root, *NIL, *ncnt;
    typedef pair<node*, node*> Droot;
    Treap() {
        ncnt = root = NIL = &pl[0];
        NIL->ch[0] = NIL->ch[1] = NIL; NIL->sum = 0;
    }
    unsigned int get_rand() {
        return (rand() << 16) | rand() ^ (rand() << 8);
    }
    node *newnode(int k, int c) {
        node *f = (++ncnt);
        f->ch[0] = f->ch[1] = NIL;
        f->pri = get_rand(), f->key = k, f->cnt = f->sum = c;
        f->tg1 = 0, f->tg2 = 1;
        return f;
    }
    void pushdown(node *x) {
        if( x->tg1 ) {
            if( x->ch[0] != NIL )
                x->ch[0]->tg1 += x->tg1, x->ch[0]->key += x->tg1;
            if( x->ch[1] != NIL )
                x->ch[1]->tg1 += x->tg1, x->ch[1]->key += x->tg1;
            x->tg1 = 0;
        }
        if( x->tg2 != 1 ) {
            if( x->ch[0] != NIL ) {
                x->ch[0]->tg2 = mul(x->ch[0]->tg2, x->tg2);
                x->ch[0]->cnt = mul(x->ch[0]->cnt, x->tg2);
                x->ch[0]->sum = mul(x->ch[0]->sum, x->tg2);
            }
            if( x->ch[1] != NIL ) {
                x->ch[1]->tg2 = mul(x->ch[1]->tg2, x->tg2);
                x->ch[1]->cnt = mul(x->ch[1]->cnt, x->tg2);
                x->ch[1]->sum = mul(x->ch[1]->sum, x->tg2);
            }
            x->tg2 = 1;
        }
    }
    void pushup(node *x) {
        x->sum = add(x->cnt, add(x->ch[0]->sum, x->ch[1]->sum));
    }
    node *merge(node *rt1, node *rt2) {
        if( rt1 == NIL ) return rt2;
        if( rt2 == NIL ) return rt1;
        pushdown(rt1), pushdown(rt2);
        if( rt1->pri < rt2->pri ) {
            rt2->ch[0] = merge(rt1, rt2->ch[0]), pushup(rt2);
            return rt2;
        }
        else {
            rt1->ch[1] = merge(rt1->ch[1], rt2), pushup(rt1);
            return rt1;
        }
    }
    Droot split(node *rt, int k) {
        if( rt == NIL ) return make_pair(NIL, NIL);
        pushdown(rt);
        if( k <= rt->key ) {
            Droot tmp = split(rt->ch[0], k);
            rt->ch[0] = tmp.second; pushup(rt);
            return make_pair(tmp.first, rt);
        }
        else {
            Droot tmp = split(rt->ch[1], k);
            rt->ch[1] = tmp.first; pushup(rt);
            return make_pair(rt, tmp.second);
        }
    }
    void insert(node *x) {
        Droot tmp = split(root, x->key);
        root = merge(merge(tmp.first, x), tmp.second);
    }
    int query(int k) {
        Droot tmp = split(root, k);
        int ret = tmp.second->sum;
        root = merge(tmp.first, tmp.second);
        return ret;
    }
    void update1(int x) {
        if( root != NIL )
            root->tg1 += x, root->key += x;
    }
    void update2(int x) {
        if( root != NIL )
            root->tg2 = mul(root->tg2, x), root->cnt = mul(root->cnt, x), root->sum = mul(root->sum, x);
    }
    void init() {
        ncnt = root = NIL;
    }
}T;
int dp[MAXN + 5], spro[MAXN + 5], inv[MAXN + 5], pos[MAXN + 5], val[MAXN + 5];
int dfs3(int x, int f, int s, int k) {
    int ret = 0;
    if( !pos[x] ) ret = mul(T.query(-s), mul(k, spro[x]));
    for(edge *p=adj[x];p;p=p->nxt) {
        if( p->to == f ) continue;
        if( pos[x] ) {
            if( pos[x] == p->to )
                ret = add(ret, dfs3(p->to, x, s + val[p->to], mul(k, spro[x])));
        }
        else ret = add(ret, dfs3(p->to, x, s + val[p->to], mul(k, mul(spro[x], inv[p->to]))));
    }
    return ret;
}
void dfs4(int x, int f, int s, int k) {
    if( !pos[x] ) T.insert(T.newnode(s, mul(k, spro[x])));
    for(edge *p=adj[x];p;p=p->nxt) {
        if( p->to == f ) continue;
        if( pos[x] ) {
            if( pos[x] == p->to )
                dfs4(p->to, x, s + val[p->to], mul(k, spro[x]));
        }
        else dfs4(p->to, x, s + val[p->to], mul(k, mul(spro[x], inv[p->to])));
    }
}
void update(int x, int y) {
    if( !dp[y] ) pos[x] = (pos[x] ? -1 : y);
    else spro[x] = mul(spro[x], dp[y]);
}
void dfs2(int x, int f, bool flag) {
    spro[x] = 1, pos[x] = 0, dp[x] = 0;
    if( !hvy[x] ) {
        inv[x] = dp[x] = (val[x] >= 0);
        if( flag )
            T.insert(T.newnode(val[x], 1));
        return ;
    }
    for(edge *p=adj[x];p;p=p->nxt) {
        if( p->to == f || p->to == hvy[x] ) continue;
        dfs2(p->to, x, false), update(x, p->to);
    }
    dfs2(hvy[x], x, true), update(x, hvy[x]);
    T.update1(val[x]);
    if( !pos[x] ) {
        T.update2(mul(spro[x], inv[hvy[x]]));
        for(edge *p=adj[x];p;p=p->nxt) {
            if( p->to == f || p->to == hvy[x] ) continue;
            dp[x] = add(dp[x], dfs3(p->to, x, val[p->to], inv[p->to]));
            dfs4(p->to, x, val[x] + val[p->to], mul(spro[x], inv[p->to]));
        }
        T.insert(T.newnode(val[x], spro[x]));
    }
    else {
        if( pos[x] == hvy[x] ) {
            T.update2(spro[x]);
            for(edge *p=adj[x];p;p=p->nxt) {
                if( p->to == f || p->to == hvy[x] ) continue;
                dp[x] = add(dp[x], dfs3(p->to, x, val[p->to], inv[p->to]));
            }
        }
        else {
            if( pos[x] != -1 ) {
                dp[x] = add(dp[x], dfs3(pos[x], x, val[pos[x]], mul(spro[x], inv[hvy[x]])));
                T.update2(0);
                dfs4(pos[x], x, val[x] + val[pos[x]], spro[x]);
                for(edge *p=adj[x];p;p=p->nxt) {
                    if( p->to == f || p->to == hvy[x] || p->to == pos[x] ) continue;
                    dp[x] = add(dp[x], dfs3(p->to, x, val[p->to], inv[p->to]));
                }
            }
            else {
                int cnt = 0; bool flag = false;
                for(edge *p=adj[x];p;p=p->nxt) {
                    if( p->to == f ) continue;
                    if( dp[p->to] == 0 ) {
                        cnt++;
                        if( p->to == hvy[x] )
                            flag = true;
                    }
                }
                if( cnt == 2 ) {
                    if( flag ) {
                        T.update2(spro[x]);
                        for(edge *p=adj[x];p;p=p->nxt) {
                            if( p->to == f ) continue;
                            if( dp[p->to] == 0 && p->to != hvy[x] )
                                dp[x] = add(dp[x], dfs3(p->to, x, val[p->to], 1));
                        }
                    }
                    else {
                        T.update2(0);
                        for(edge *p=adj[x];p;p=p->nxt) {
                            if( p->to == f ) continue;
                            if( dp[p->to] == 0 ) {
                                if( !flag ) {
                                    dfs4(p->to, x, val[x] + val[p->to], spro[x]);
                                    flag = true;
                                }
                                else dp[x] = add(dp[x], dfs3(p->to, x, val[p->to], 1));
                            }
                        }
                    }
                }
                T.update2(0);
            }
        }
    }
    dp[x] = add(dp[x], T.query(0)), inv[x] = pow_mod(dp[x], MOD-2);
    if( !flag ) T.init();
}
void solve() {
    int n; scanf("%d", &n);
    for(int i=1;i<=n;i++)
        scanf("%d", &val[i]), adj[i] = NULL;
    ecnt = &edges[0];
    for(int i=1;i<n;i++) {
        int x, y; scanf("%d%d", &x, &y);
        addedge(x, y);
    }
    int rt = T.get_rand() % n + 1;
    dfs1(rt, 0), dfs2(rt, 0, false);
    printf("%d\n", dp[rt]);
}
int main() {
    int t; scanf("%d", &t);
    srand(20041112^t);
    while( t-- ) solve();
}

@details@

Long time no write treap a non-rotating (? Wrote it), when the merge written by his son about the relationship between the value of the right to the root of the decision. . .
Because only the right stack only meet the maximum root, root can only compare weights. . . If the right balance two roots of value as not to explode. . .
Correct wording is not considering weights when you merge, you can ensure the relative size of the two balanced relationship tree when calling merge.

Guess you like

Origin www.cnblogs.com/Tiw-Air-OAO/p/11343615.html