zoukankan      html  css  js  c++  java
  • BZOJ 4127 Abs 解题报告

    这个题感觉很厉害的样子。。

    首先我们注意到一点:每次加的 $d$ 都是非负的。

    那么就说明一个数只可能从负数变成非负数并且只会变一次。

    所以我们就可以暴力地去改变一个数的正负情况。

    然后我们就可以用树链剖分,维护一下区间的最大负数和负数的个数就可以了。

    时间复杂度 $O(nlog^2 n)$,空间复杂度 $O(n)$。

      1 #include <cstdio>
      2 typedef long long LL;
      3 #define N 262144 + 5
      4 #define INF 1234567890987654321LL
      5 
      6 int n, m, tot, cnt, A[N], Head[N], Root[N], Fa[N], Ad[N], Pos[N], Num[N], Dfn[N], Len[N], Size[N], Son[N], q[N];
      7 
      8 struct Edge
      9 {
     10     int next, node;
     11 }E[N];
     12 
     13 struct Segment_Tree
     14 {
     15     int l, r, neg_cnt;
     16     LL sum, delta, neg_Max;
     17 }h[N];
     18 
     19 inline void addedge(int u, int v)
     20 {
     21     E[++ tot].next = Head[u], Head[u] = tot;
     22     E[tot].node = v;
     23     E[++ tot].next = Head[v], Head[v] = tot;
     24     E[tot].node = u;
     25 }
     26 
     27 inline LL Abs(LL x)
     28 {
     29     return x > 0 ? x : -x;
     30 }
     31 
     32 inline void dfs(int z)
     33 {
     34     Size[z] = 1;
     35     for (int i = Head[z]; i; i = E[i].next)
     36     {
     37         int d = E[i].node;
     38         if (d == Fa[z]) continue ;
     39         Fa[d] = z;
     40         dfs(d);
     41         Size[z] += Size[d];
     42     }
     43     for (int i = Head[z]; i; i = E[i].next)
     44     {
     45         int d = E[i].node;
     46         if (d == Fa[z]) continue ;
     47         if (!Son[z] || Size[d] > Size[Son[z]])
     48             Son[z] = d;
     49     }
     50 }
     51 
     52 inline void update(int x)
     53 {
     54     h[x].sum = h[h[x].l].sum + h[h[x].r].sum;
     55     h[x].neg_Max = h[h[x].l].neg_Max > h[h[x].r].neg_Max ? h[h[x].l].neg_Max : h[h[x].r].neg_Max;
     56     h[x].neg_cnt = h[h[x].l].neg_cnt + h[h[x].r].neg_cnt;
     57 }
     58 
     59 inline void Build(int &x, int l, int r)
     60 {
     61     if (!x) x = ++ tot;
     62     if (l == r)
     63     {
     64         h[x].sum = Abs(A[q[l]]);
     65         if (A[q[l]] < 0) h[x].neg_Max = A[q[l]], h[x].neg_cnt = 1;
     66             else h[x].neg_Max = -INF;
     67         return ;
     68     }
     69     int mid = l + r >> 1;
     70     Build(h[x].l, l, mid);
     71     Build(h[x].r, mid + 1, r);
     72     update(x);
     73 }
     74 
     75 inline void apply(int x, int l, int r, LL d)
     76 {
     77     h[x].sum += d * (r - l + 1 - h[x].neg_cnt * 2);
     78     h[x].delta += d;
     79     h[x].neg_Max += d;
     80 }
     81 
     82 inline void push(int x, int l, int r)
     83 {
     84     if (h[x].delta)
     85     {
     86         int mid = l + r >> 1;
     87         apply(h[x].l, l, mid, h[x].delta);
     88         apply(h[x].r, mid + 1, r, h[x].delta);
     89         h[x].delta = 0;
     90     }
     91 }
     92 
     93 inline void Point_Modify(int x, int l, int r, LL d)
     94 {
     95     if (l == r)
     96     {
     97         h[x].sum = -h[x].sum;
     98         h[x].neg_Max = -INF;
     99         h[x].neg_cnt = 0;
    100         return ;
    101     }
    102     int mid = l + r >> 1;
    103     push(x, l, r);
    104     if (h[h[x].l].neg_Max > h[h[x].r].neg_Max)
    105         Point_Modify(h[x].l, l, mid, d);
    106     else Point_Modify(h[x].r, mid + 1, r, d);
    107     update(x);
    108 }
    109 
    110 inline void Modify(int x, int l, int r, int s, int t, LL d)
    111 {
    112     if (l == s && r == t)
    113     {
    114         while (h[x].neg_Max >= -d)
    115             Point_Modify(x, l, r, d);
    116         apply(x, l, r, d);
    117         return ;
    118     }
    119     push(x, l, r);
    120     int mid = l + r >> 1;
    121     if (t <= mid) Modify(h[x].l, l, mid, s, t, d);
    122         else if (s > mid) Modify(h[x].r, mid + 1, r, s, t, d);
    123         else Modify(h[x].l, l, mid, s, mid, d), Modify(h[x].r, mid + 1, r, mid + 1, t, d);
    124     update(x);
    125 }
    126 
    127 inline LL Query(int x, int l, int r, int s, int t)
    128 {
    129     if (l == s && r == t) return h[x].sum;
    130     push(x, l, r);
    131     int mid = l + r >> 1;
    132     if (t <= mid) return Query(h[x].l, l, mid, s, t);
    133         else if (s > mid) return Query(h[x].r, mid + 1, r, s, t);
    134         else return Query(h[x].l, l, mid, s, mid) + Query(h[x].r, mid + 1, r, mid + 1, t);
    135 }
    136 
    137 inline void Prepare()
    138 {
    139     tot = 0;
    140     for (int i = 1; i <= n; i ++)
    141     {
    142         if (Ad[i]) continue ;
    143         Dfn[i] = Dfn[Fa[i]] + 1;
    144         q[0] = 0;
    145         cnt ++;
    146         for (int x = i; x; x = Son[x])
    147         {
    148             Ad[x] = i, Pos[x] = ++ Len[cnt];
    149             Num[x] = cnt, Dfn[x] = Dfn[i];
    150             q[++ q[0]] = x;
    151         }
    152         Build(Root[cnt], 1, Len[cnt]);
    153     }
    154 }
    155 
    156 int main()
    157 {
    158     #ifndef ONLINE_JUDGE
    159         freopen("4127.in", "r", stdin);
    160         freopen("4127.out", "w", stdout);
    161     #endif
    162     
    163     scanf("%d%d", &n, &m);
    164     for (int i = 1; i <= n; i ++)
    165         scanf("%d", A + i);
    166     for (int i = 1, u, v; i < n; i ++)
    167     {
    168         scanf("%d%d", &u, &v);
    169         addedge(u, v);
    170     }
    171     dfs(1);
    172     Prepare();
    173     for (int op, u, v; m; m --)
    174     {
    175         scanf("%d", &op);
    176         if (op == 1)
    177         {
    178             LL d;
    179             scanf("%d%d%lld", &u, &v, &d);
    180             if (Dfn[u] < Dfn[v]) u = u - v, v = u + v, u = v - u;
    181             for (; Dfn[u] > Dfn[v]; u = Fa[Ad[u]])
    182                 Modify(Root[Num[u]], 1, Len[Num[u]], 1, Pos[u], d);
    183             for (; Ad[u] != Ad[v]; u = Fa[Ad[u]], v = Fa[Ad[v]])
    184             {
    185                 Modify(Root[Num[u]], 1, Len[Num[u]], 1, Pos[u], d);
    186                 Modify(Root[Num[v]], 1, Len[Num[v]], 1, Pos[v], d);
    187             }
    188             if (Pos[u] > Pos[v]) u = u - v, v = u + v, u = v - u;
    189             Modify(Root[Num[u]], 1, Len[Num[u]], Pos[u], Pos[v], d);
    190         }
    191         else
    192         {
    193             scanf("%d%d", &u, &v);
    194             LL ans = 0;
    195             if (Dfn[u] < Dfn[v]) u = u - v, v = u + v, u = v - u;
    196             for (; Dfn[u] > Dfn[v]; u = Fa[Ad[u]])
    197                 ans += Query(Root[Num[u]], 1, Len[Num[u]], 1, Pos[u]);
    198             for (; Ad[u] != Ad[v]; u = Fa[Ad[u]], v = Fa[Ad[v]])
    199             {
    200                 ans += Query(Root[Num[u]], 1, Len[Num[u]], 1, Pos[u]);
    201                 ans += Query(Root[Num[v]], 1, Len[Num[v]], 1, Pos[v]);
    202             }
    203             if (Pos[u] > Pos[v]) u = u - v, v = u + v, u = v - u;
    204             ans += Query(Root[Num[u]], 1, Len[Num[u]], Pos[u], Pos[v]);
    205             printf("%lld
    ", ans);
    206         }
    207     }
    208     
    209     #ifndef ONLINE_JUDGE
    210         fclose(stdin);
    211         fclose(stdout);
    212     #endif
    213     return 0;
    214 }
    4127_Gromah
  • 相关阅读:
    GSM Arena 魅族mx四核评测个人翻译
    Oracle Exists用法|转|
    NC公有协同的实现原理|同13的QQ||更新总部往来协同|
    NC客商bd_custbank不可修改账号、名称但可修改默认银行并更新分子公司trigger
    试玩了plsql中test窗口declare声明变量|lpad函数||plsql sql command test window区别|
    使用windows live writer测试
    用友写insert on bd_custbank 触发器和自动更新单位名称2in1
    oracle触发器select into和cursor用法的区别
    |转|oracle中prior的用法,connect by prior,树形目录
    客商增加自动增加银行账户|搞定!||更新使用游标course写法|
  • 原文地址:https://www.cnblogs.com/gromah/p/4599205.html
Copyright © 2011-2022 走看看