学长'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+来写暴力.....)

posted @ 2019-10-08 20:52  sky20030724  阅读(159)  评论(0编辑  收藏  举报