ディレクトリ
@説明@
整数を書くために各ノードで無根ツリーを考えます。
あなたの仕事は、各ノードが正確に一つのパス、および各パスと非負上のノードの数の和に属しているように、これらの木は、いくつかのパスに分けることができますどのように多くの方法数えることです。
入力フォーマット
最初のラインの入力データは、整数のTを含むデータセットの数を表します。
データの次のセットはTです。各データの最初の行は、整数N、ツリー内のノードの代表番号を含みます。
次の行は、スペースで区切られた、N個の整数を含む各ノードの書き込みの数を表します。
次のN-1行は、各行は代表番号とXjのYjと直接接続されたノード間にエッジが存在することを、二つの整数XjのとYjとを含みます。
出力形式
整数を含む各試験について、出力ライン、得られた^ 9の結果+7モジュロツリー分解スキーム10の数です。
データ範囲とサブタスク
•^。1. 5≤T≤10
。1、Yjの≤Nの•≤Xjの
サンプルデータ
入力
。1 4
。1 5 10 -1
。1 2
。1 3
2 4
出力
4
サンプル説明
:分解法4種類の合計を
経路全域木であります、そして+ 10 5 + +である1(-1)= 15;
ノード2および4を含むパスを•、和は10 +( 。-1)= 9;他の経路は、ノード1および3、および=を含む5 6 + 1、
ノード1,2、および4を含むパスを•、和は10 + 1 +( - 1)= 10;その他パスはノード3を含み、それは5;
•ノード2および4を含む第一の経路は、和は10 +(-1)= 9;第二の経路が1でノード1を含み、条パスはノード3を含み、これは3です。
@溶液@
[x]は爆発し、xは法的なプログラムサブツリーの根の数であるDPの定義:第一に、簡単なDPと考えられます。
xが0の転送チェーンであるとき、LCAを列挙するために、すべての支出の枝のDPのバリューチェーンは、乗るために上がります。
この方法は、O(N ^ 2)で行い、最適化を検討してください。
私たちは、ヒューリスティックの使用は、当社のバランス列挙チェーン・プロセスを最適化するために+ツリーをマージすることができ考えます。
処理されたバリオンレプトンツリーの継承ツリーを考えてみましょう、我々は維持バリオン息子は木の製品の各DPのバリューチェーンと現在のポイントや枝の重みを登っ。
タグを再生することにより、光のプログラムサブツリーの数を乗じ鎖重みとval現在の点に結合されたそれぞれの製品のDP値。
そして、レプトンツリーに取り組むことを検討してください。軽鎖統計サブツリーの一端、他端が現在のツリーにおける場合のバランスを維持します。
この実施形態は、木の部分木の数を維持し、+ <Kと> 2つの平衡ツリーの= Kに体重分割をバランスさせ、そして答えを得るために> = kのバランスの取れたツリーを取ることができます。
その後、ツリーのすべてのバランスに投げツリーレプトンツリーチェーンを置きます。
最後に、現在のルートが追加され、その後、平衡ツリーとプログラムチェーンの> = 0数に重みを除去するために覚えている(すなわち、チェーンのエンドポイントは、現在の点です)。
完璧に見えるが、一つの問題がある:0の場合にはDP値(それ自体が又は少数多すぎるMOD 10 ^ 9 + 7 = 0プログラムすることができるかもしれないプログラム ) 逆元が存在していないが。
もちろん、ソリューションの多くが、私は最も簡単な(最もSB)ソリューションを選択しました:それは0のDP息子の値を持っているどのくらいかを決定します。
合計0のスキームの数、またはカテゴリの話で明らかつ以上の多くの場合、WAは人生を疑うします。。。
@acceptedコード@
#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();
}
@詳細@
マージは、意思決定のルートに右の値との関係についての彼の息子が書いたときに、非回転treap久しぶりの書き込みは、(?それを書きました)。。。
唯一の右のスタックが唯一最大のルートを満たしているため、ルートが重みを比較することしかできません。。。値の適切なバランス2本の根があれば爆発しないように。。。
正しい言葉遣いを使用すると、マージするとき、マージを呼び出すとき、あなたは2つの平衡関係ツリーの相対的な大きさを確保することができ重みを考慮していません。