学长's 考试 - T2 权值线段树+线段树合并
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 using namespace std; 5 const int N = 120000; 6 #define Max(a, b) ((a) > (b) ? (a) : (b)) 7 #define ll long long 8 ll head[N], nex[N << 1], to[N << 1], val[N << 1]; 9 ll cnt; 10 ll ans1[N], ans2[N]; 11 ll a[N], k[N], rt[N]; 12 ll n; 13 void addedge(ll a, ll b, ll v) 14 { 15 nex[++ cnt] = head[a]; 16 head[a] = cnt; 17 to[cnt] = b; 18 val[cnt] = v; 19 } 20 struct node 21 { 22 ll tot; 23 #define rs(x) tree[x].rs 24 #define ls(x) tree[x].ls 25 struct nd 26 { 27 ll rt, dis, maxx, num; 28 ll siz, laz; 29 ll ls, rs; 30 }tree[N * 40]; 31 void push_up(ll x, ll del) 32 { 33 tree[x].laz += del; 34 tree[x].rt += del * tree[x].num; 35 } 36 void push_down(ll x, ll l, ll r) 37 { 38 if(tree[x].laz) 39 { 40 if(ls(x)) 41 push_up(ls(x), tree[x].laz); 42 if(rs(x)) 43 push_up(rs(x), tree[x].laz); 44 tree[x].laz = 0; 45 } 46 } 47 ll merge(ll l, ll r, ll u, ll v) 48 { 49 if(!u || !v) 50 return u + v; 51 push_down(u, l, r); 52 push_down(v, l, r); 53 ll now = ++ tot; 54 tree[now].dis = tree[u].dis + tree[v].dis + tree[u].num * tree[v].rt + tree[u].rt * tree[v].num; 55 tree[now].num = tree[u].num + tree[v].num; 56 tree[now].rt = tree[u].rt + tree[v].rt; 57 tree[now].maxx = Max(tree[u].maxx, tree[v].maxx); 58 if(l == r) 59 { 60 if(tree[now].num) 61 tree[now].siz = 1; 62 tree[now].maxx = tree[now].dis; 63 return now; 64 } 65 ll mid = (l + r) >> 1; 66 tree[now].ls = merge(l, mid, tree[u].ls, tree[v].ls); 67 tree[now].rs = merge(mid + 1, r, tree[u].rs, tree[v].rs); //!!!!! 68 tree[now].siz = tree[tree[now].ls].siz + tree[tree[now].rs].siz; 69 tree[now].maxx = Max(tree[tree[now].ls].maxx, tree[tree[now].rs].maxx); 70 return now; 71 } 72 ll solve(ll l, ll r, ll x) 73 { 74 if(l == r) 75 { 76 return l; 77 } 78 ll mid = (l + r) >> 1; 79 push_down(x, l, r); 80 if(l <= mid && tree[ls(x)].siz && tree[ls(x)].maxx == tree[x].maxx) // !!!! 81 return solve(l, mid, ls(x)); 82 else 83 return solve(mid + 1, r, rs(x)); 84 } 85 void update(ll &x, ll l, ll r, ll v) 86 { 87 if(!x) 88 x = ++ tot; 89 if(l == r) 90 { 91 tree[x].siz = 1; 92 tree[x].num = 1; 93 return ; 94 } 95 push_down(x, l, r); 96 ll mid = (l + r) >> 1; 97 if(v <= mid) 98 update(ls(x), l, mid, v); 99 else 100 update(rs(x), mid + 1, r, v); 101 tree[x].maxx = Max(tree[ls(x)].maxx, tree[rs(x)].maxx); 102 tree[x].siz = tree[ls(x)].siz + tree[rs(x)].siz; 103 } 104 ll dfs2(ll l, ll r, ll x, ll idx) 105 { 106 if(l == r) 107 return tree[x].dis; 108 ll mid = (l + r) >> 1; 109 push_down(x, l, r); 110 ll siz = tree[ls(x)].siz; 111 // printf("%lld test\n", siz); 112 if(siz >= idx) 113 return dfs2(l, mid, ls(x), idx); 114 else 115 return dfs2(mid + 1, r, rs(x), idx - siz); 116 } 117 }seg; 118 void dfs(ll x, ll fa, ll v) 119 { 120 seg.update(rt[x], 1, n, a[x]); 121 for(ll i = head[x] ; i ; i = nex[i]) 122 if(to[i] != fa) 123 dfs(to[i], x, val[i]); 124 if(seg.tree[rt[x]].siz < k[x]) 125 ans2[x] = -1; 126 else 127 ans2[x] = seg.dfs2(1, n, rt[x], k[x]); 128 ans1[x] = seg.solve(1, n, rt[x]); 129 seg.push_up(rt[x], v); 130 rt[fa] = seg.merge(1, n, rt[x], rt[fa]); 131 } 132 int main() 133 { 134 scanf("%lld", &n); 135 for(ll i = 1 ; i < n ; i ++) 136 { 137 ll a, b, v; 138 scanf("%lld%lld%lld", &a, &b, &v); 139 addedge(a, b, v); 140 addedge(b, a, v); 141 } 142 for(ll i = 1 ; i <= n ; i ++) 143 scanf("%lld", &a[i]); 144 for(ll i = 1 ; i <= n ; i ++) 145 scanf("%lld", &k[i]); 146 dfs(1, 0, 0); 147 for(ll i = 1 ; i <= n ; i ++) 148 printf("%lld %lld\n", ans1[i], ans2[i]); 149 return 0; 150 }
主要在于总结错误, 带!的地方均为开始时有问题的(现已更正)。
另外听说线段树合并已经下放到NOIp知识点中了。 需要多练,还可以顺便提高码力。
(现在的暴力能力太差了,需要留1.5h+来写暴力.....)