zoukankan      html  css  js  c++  java
  • 【Code Chef】April Challenge 2019

    Subtree Removal

    很显然不可能选择砍掉一对有祖先关系的子树。令$f_i$表示$i$子树的答案,如果$i$不被砍,那就是$a_i + sumlimits_j f_j$;如果$i$被砍,那就是$-x$。取个$max$就好了。

    时间、空间复杂度$O(n)$。

    #include <bits/stdc++.h>
    
    using namespace std;
    
    const int N = 1e5 + 5;
    
    int tc, n, xx;
    int a[N];
    vector<int> g[N];
    long long f[N];
    
    void Dfs(int x, int ft) {
      f[x] = a[x];
      for (int i = 0; i < g[x].size(); ++i) {
        int v = g[x][i];
        if (v == ft) continue;
        Dfs(v, x);
        f[x] += f[v];
      }
      f[x] = max(f[x], -(long long)xx);
    }
    
    int main() {
      scanf("%d", &tc);
      for (; tc--; ) {
        scanf("%d%d", &n, &xx);
        for (int i = 1; i <= n; ++i) {
          scanf("%d", &a[i]);
        }
        for (int i = 1, x, y; i < n; ++i) {
          scanf("%d%d", &x, &y);
          g[x].push_back(y);
          g[y].push_back(x);
        }
    
        Dfs(1, 0);
        printf("%lld
    ", f[1]);
        
        // remember to clear up
        for (int i = 1; i <= n; ++i) {
          g[i].clear();
        }
      }
      
      return 0;
    }
    View Code

    Playing with Numbers

    在模$m$意义下,$a * k(k in mathbb{N})$能表示的最大的数就是$m - (a, m)$。容易推导出一个叶子的答案就是$m_i - (m, a_{b_1}, a_{b_2}, ... , a_{b_w})$,其中$b$表示$i$号点的祖先链。

    时间复杂度$O(nlogn)$,空间复杂度$O(n)$。

    #include <bits/stdc++.h>
    
    using namespace std;
    
    const int N = 1e5 + 5;
    
    int tc, n;
    vector<int> g[N];
    long long a[N], m[N], gcd[N];
    
    void Dfs(int x, int ft) {
      for (int i = 0; i < g[x].size(); ++i) {
        int v = g[x][i];
        if (v == ft) continue;
        gcd[v] = __gcd(gcd[x], a[v]);
        Dfs(v, x);
      }
    }
    
    int main() {
      scanf("%d", &tc);
      for (; tc--; ) {
        scanf("%d", &n);
        for (int i = 1, x, y; i < n; ++i) {
          scanf("%d%d", &x, &y);
          g[x].push_back(y);
          g[y].push_back(x);
        }
        for (int i = 1; i <= n; ++i) {
          scanf("%lld", &a[i]);
        }
        for (int i = 1; i <= n; ++i) {
          scanf("%lld", &m[i]);
        }
        gcd[1] = a[1];
        Dfs(1, 0);
    
        for (int i = 2; i <= n; ++i) {
          if (g[i].size() == 1) {
            long long d = __gcd(gcd[i], m[i]);
            printf("%lld ", m[i] - d);
          }
        }
        printf("
    ");
        
        // remember to clear up
        for (int i = 1; i <= n; ++i) {
          g[i].clear();
        }
      }
      
      return 0;
    }
    View Code

    Kira Loves Palindromes

    令$f_{i,j}$表示以$i,j$为端点分别向左右两边扩展最长能匹配的长度。题目要求两个子串$s1, s2$拼起来是回文串的数量,我们假设其回文中心在$s2$里(在$s1$的话反过来在做一遍即可),我们枚举$s2$的左端点的位置$i$,在枚举回文中心的右端点$j$,则此时有方案数$sumlimits_{k = 1}^{i - 1} f_{k, j + 1}$。对$f$做个前缀和,外面枚举个$i,j$即可。

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

    #include <bits/stdc++.h>
    
    using namespace std;
    
    typedef unsigned long long ULL;
    
    const int N = 1e3 + 5;
    const ULL BAS = 137;
    
    int n;
    char s[N];
    int f[N][N], s1[N][N], s2[N][N];
    long long ans;
    ULL H[N], hz[N], hv[N];
    
    ULL Get(int l, int r, ULL *h) {
      return (h[r] - h[l - 1]) * H[N - l];
    }
    
    bool Chkp(int l, int r) {
      if (l > r) return 1;
      int d = (r - l + 1) / 2;
      return Get(l, l + d - 1, hz) == Get(n - r + 1, n - r + d, hv);
    }
    
    int main() {
      H[0] = 1;
      for (int i = 1; i < N; ++i) {
        H[i] = H[i - 1] * BAS;
      }
      
      scanf("%s", s + 1);
      n = strlen(s + 1);
      for (int i = 1; i <= n; ++i) {
        hz[i] = hz[i - 1] + H[i] * s[i];
        hv[i] = hv[i - 1] + H[i] * s[n - i + 1];
      }
    
      for (int i = 1; i <= n; ++i) {
        for (int j = n; j > i; --j) {
          if (s[i] == s[j]) {
            f[i][j] = f[i - 1][j + 1] + 1;
          }
        }
      }
      for (int i = 1; i <= n; ++i) {
        for (int j = n; j > i; --j) {
          s1[i][j] = s1[i][j + 1] + f[i][j];
        }
      }
      for (int j = 1; j <= n; ++j) {
        for (int i = 1; i < j; ++i) {
          s2[i][j] = s2[i - 1][j] + f[i][j];
        }
      }
      
      for (int i = 2; i <= n; ++i) {
        for (int j = i; j <= n; ++j) {
          if (!Chkp(i, j - 1)) continue;
          ans += s2[i - 1][j];
        }
      }
      for (int i = 1; i < n; ++i) {
        for (int j = 1; j < i; ++j) {
          if (!Chkp(j + 1, i)) continue;
          ans += s1[j][i + 1];
        }
      }
    
      printf("%lld
    ", ans);
      
      return 0;
    }
    View Code

    Offer for Chef

    题中的那个运算就是位运算与,然后有用的位置只有$50$个(即如果$k$大于$t$中非$0$个数答案就是$0$)。可以考虑诸位确定,$check$时写个$f_{i,j}$表示把前$i$个数分成$j$段,每段和都是当前要$check$的数的母集即可。

    时间复杂度$O(50^4)$,空间复杂度$O(n)$。

    #include <bits/stdc++.h>
    
    using namespace std;
    
    const int N = 1e5 + 5;
    const int M = 53;
    
    int n, nq, k;
    int t[N];
    long long a[N];
    set<long long> f[M][M];
    
    int main() {
      scanf("%d", &n);
      for (int i = 1; i <= n; ++i) {
        scanf("%lld", &a[i]);
      }
    
      scanf("%d", &nq);
      for (; nq--; ) {
        scanf("%d", &k);
        vector<long long> w, sw;
        long long tmp = 0;
        for (int i = 1; i <= n; ++i) {
          scanf("%d", &t[i]);
          if (t[i]) {
            w.push_back(a[i] * t[i]);
            tmp += a[i] * t[i];
            sw.push_back(tmp);
          }
        }
        
        if (k > w.size()) {
          printf("0
    ");
          continue;
        }
    
        for (int i = 0; i < M; ++i) {
          for (int j = 0; j < M; ++j) {
            f[i][j].clear();
          }
        }
        for (int i = 0; i < w.size(); ++i) {
          f[i][1].insert(sw[i]);
        }
        
        for (int i = 0; i < w.size(); ++i) {
          for (int j = 1; j < k; ++j) {
            for (int l = i + 1; l < w.size(); ++l) {
              for (long long e : f[i][j]) {
                f[l][j + 1].insert(e & (sw[l] - sw[i]));
              }
            }
          }
        }
        printf("%lld
    ", *f[w.size() - 1][k].rbegin());
      }
      
      return 0;
    }
    View Code

    Mininum XOR over Tree

    不说了,直接$trie$树合并。

    时间、空间复杂度$O(nlogn)$。

    #include <bits/stdc++.h>
    
    using namespace std;
    
    const int T = 20;
    const int N = 2e5 + 5;
    const int M = N * T * 2;
    
    struct Node {
      int ch[2], idm;
    } node[M];
    
    int tc, n, m, nq, tot;
    int w[N], rt[N];
    vector<int> g[N];
    
    int Chkmin(int x, int y) {
      if (!x || !y) return x | y;
      return min(x, y);
    }
    
    void Ins(int x) {
      rt[x] = ++tot;
      int p = rt[x];
      for (int i = T - 1; ~i; --i) {
        int c = w[x] >> i & 1;
        if (!node[p].ch[c]) {
          node[p].ch[c] = ++tot;
        }
        p = node[p].ch[c];
      }
      node[p].idm = x;
    }
    
    int Merge(int x, int y) {
      if (!x || !y) return x | y;
      int z = ++tot;
      node[z].ch[0] = Merge(node[x].ch[0], node[y].ch[0]);
      node[z].ch[1] = Merge(node[x].ch[1], node[y].ch[1]);
      node[z].idm = Chkmin(node[x].idm, node[y].idm);
      return z;
    }
    
    void Dfs(int x, int ft) {
      Ins(x);
      for (int i = 0; i < g[x].size(); ++i) {
        int v = g[x][i];
        if (v == ft) continue;
        Dfs(v, x);
        rt[x] = Merge(rt[x], rt[v]);
      }
    }
    
    int main() {
      scanf("%d", &tc);
      for (; tc--; ) {
        scanf("%d%d", &n, &nq);
        for (int i = 1; i <= n; ++i) {
          scanf("%d", &w[i]);
        }
        for (int i = 1, x, y; i < n; ++i) {
          scanf("%d%d", &x, &y);
          g[x].push_back(y);
          g[y].push_back(x);
        }
        Dfs(1, 0);
    
        int lid = 0, lval = 0;
        for (int x, v; nq--; ) {
          scanf("%d%d", &x, &v);
          x ^= lid;
          v ^= lval;
          int p = rt[x], val = 0;
          for (int i = T - 1; ~i; --i) {
            int c = v >> i & 1;
            if (node[p].ch[c ^ 1]) {
              val += 1 << i;
              p = node[p].ch[c ^ 1];
            } else {
              p = node[p].ch[c];
            }
          }
          lid = node[p].idm;
          lval = val;
          printf("%d %d
    ", lid, lval);
        }
        
        // remember to clear up
        for (int i = 1; i <= tot; ++i) {
          node[i].ch[0] = node[i].ch[1] = node[i].idm = 0;
        }
        tot = 0;
        for (int i = 1; i <= n; ++i) {
          g[i].clear();
          rt[i] = 0;
        }
      }
      
      return 0;
    }
    View Code

    Edgy

    考虑边的联通块个数就是$n - $所有出边颜色都相同的点的个数$+1$。我们只需要维护所有出边颜色都相同的点的个数即可。先轻重链剖分,令$nat_x$表示所有连向虚儿子的边的颜色种类(用$0$表示没有虚儿子,用$1,2$分别表示全都是$0/1$,用$3$表示$0/1$都有),然后每个点最多还剩下两条边(连向父亲的和连向重儿子的),只有这两条边的颜色和$nat$匹配才会算贡献。我们可以在树链上建线段树,维护翻转标记的同时维护区间内有贡献的点的个数。每次修改拆成两条到根的链,在线段树上执行区间翻转即可。注意,翻转轻边时候可能会修改该边上端点的$nat$值。

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

    #include <bits/stdc++.h>
    
    using namespace std;
    
    const int N = 1e5 + 5;
    
    int tc, n, nq, clk, ans;
    int fa[N], fw[N], si[N], so[N], tp[N];
    int dfn[N], li[N], nat[N], cnt[N][2];
    vector<pair<int, bool> > g[N];
    
    bool Satis(int x, int a, int b) {
      if (a != b) return 0;
      if (!nat[x] || nat[x] == a + 1) return 1;
      return 0;
    }
    
    namespace S {
      const int M = N * 4;
      struct Node {
        int zl, zr, zsum, revsum, flp;
      } node[M];
    
      vector<pair<Node, int> > qry;
    
      void Up(int t, int md) {
        Node &now = node[t];
        Node &ls = node[t << 1];
        Node &rs = node[t << 1 | 1];
        now.zl = ls.zl;
        now.zr = rs.zr;
        now.zsum = ls.zsum + rs.zsum + Satis(li[md], ls.zr, rs.zl);
        now.revsum = ls.revsum + rs.revsum + Satis(li[md], ls.zr ^ 1, rs.zl ^ 1);
      }
    
      void Uflp(int t) {
        Node &now = node[t];
        now.zl ^= 1;
        now.zr ^= 1;
        now.flp ^= 1;
        swap(now.zsum, now.revsum);
      }
    
      void Down(int t) {
        if (node[t].flp) {
          Uflp(t << 1);
          Uflp(t << 1 | 1);
          node[t].flp = 0;
        }
      }
      
      void Build(int t, int l, int r) {
        Node &now = node[t];
        now.zsum = now.revsum = now.flp = 0;
        if (l == r) {
          now.zl = now.zr = fw[li[l]];
          return;
        }
        int md = (l + r) >> 1;
        Build(t << 1, l, md);
        Build(t << 1 | 1, md + 1, r);
        Up(t, md);
      }
    
      void Flip(int t, int l, int r, int L, int R) {
        if (L <= l && r <= R) {
          Uflp(t);
          return;
        }
        int md = (l + r) >> 1;
        Down(t);
        if (L <= md) Flip(t << 1, l, md, L, R);
        if (R > md) Flip(t << 1 | 1, md + 1, r, L, R);
        Up(t, md);
      }
      
      void Modify(int t, int l, int r, int x) {
        if (l == r) return;
        int md = (l + r) >> 1;
        Down(t);
        if (x < md) Modify(t << 1, l, md, x);
        if (x > md) Modify(t << 1 | 1, md + 1, r, x);
        Up(t, md);
      }
    
      void Query(int t, int l, int r, int L, int R) {
        if (L <= l && r <= R) {
          qry.push_back(pair<Node, int>(node[t], r));
          return;
        }
        int md = (l + r) >> 1;
        Down(t);
        if (L <= md) Query(t << 1, l, md, L, R);
        if (R > md) Query(t << 1 | 1, md + 1, r, L, R);
      }
    
      int Ask(int t, int l, int r, int x) {
        if (l == r) return node[t].zl;
        int md = (l + r) >> 1;
        Down(t);
        if (x <= md) return Ask(t << 1, l, md, x);
        return Ask(t << 1 | 1, md + 1, r, x);
      }
    
      int Query(int L, int R) {
        if (L > R) return 0;
        qry.clear();
        Query(1, 1, n, L, R);
        int ret = 0;
        for (int i = 0; i < qry.size(); ++i) {
          ret += qry[i].first.zsum;
          if (i) {
            ret += Satis(li[qry[i - 1].second], qry[i - 1].first.zr, qry[i].first.zl);
          }
        }
        return ret;
      }
    }
    
    bool Chk(int x) {
      if (x == 1) {
        int ws = S::Ask(1, 1, n, dfn[so[x]]);
        return Satis(x, ws, ws);
      }
      if (!so[x]) {
        int w = S::Ask(1, 1, n, dfn[x]);
        return Satis(x, w, w);
      } else {
        int w = S::Ask(1, 1, n, dfn[x]);
        int ws = S::Ask(1, 1, n, dfn[so[x]]);
        return Satis(x, ws, w);
      }
    }
    
    void Wish(int x) {
      if (cnt[x][0] && cnt[x][1]) {
        nat[x] = 3;
      } else if (cnt[x][0]) {
        nat[x] = 1;
      } else if (cnt[x][1]) {
        nat[x] = 2;
      }
    }
    
    void Dfs0(int x) {
      si[x] = 1;
      for (int i = 0; i < g[x].size(); ++i) {
        int v = g[x][i].first, w = g[x][i].second;
        if (v == fa[x]) continue;
        fa[v] = x;
        fw[v] = w;
        Dfs0(v);
        si[x] += si[v];
        if (si[v] > si[so[x]]) so[x] = v;
      }
    }
    
    void Dfs1(int x, int gr) {
      tp[x] = gr;
      dfn[x] = ++clk;
      li[clk] = x;
      if (so[x]) Dfs1(so[x], gr);
      for (int i = 0; i < g[x].size(); ++i) {
        int v = g[x][i].first;
        if (v != fa[x] && v != so[x]) {
          Dfs1(v, v);
          ++cnt[x][g[x][i].second];
        }
      }
      Wish(x);
    }
    
    void Flip(int u) {
      for (int x = u; x; x = fa[tp[x]]) {
        ans -= S::Query(dfn[tp[x]] + 1, dfn[x]);
        ans -= Chk(tp[x]) + (tp[x] != x? Chk(x) : 0);
      }
      for (int x = u; x; x = fa[tp[x]]) {
        int z = tp[x];
        int y = fa[z];
        if (y) {
          int w = S::Ask(1, 1, n, dfn[z]);
          --cnt[y][w];
          ++cnt[y][w ^ 1];
          Wish(y);
          S::Modify(1, 1, n, dfn[y]);
        }
        S::Flip(1, 1, n, dfn[tp[x]], dfn[x]);
      }
      for (int x = u; x; x = fa[tp[x]]) {
        ans += S::Query(dfn[tp[x]] + 1, dfn[x]);
        ans += Chk(tp[x]) + (tp[x] != x? Chk(x) : 0);
      }
    }
    
    int main() {
      scanf("%d", &tc);
      for (; tc--; ) {
        scanf("%d", &n);
        for (int i = 1, x, y, z; i < n; ++i) {
          scanf("%d%d%d", &x, &y, &z);
          g[x].push_back(pair<int, bool>(y, z));
          g[y].push_back(pair<int, bool>(x, z));
        }
    
        Dfs0(1);
        Dfs1(1, 1);
        S::Build(1, 1, n);
    
        ans = 0;
        for (int i = 1; i <= n; ++i) {
          if (!so[i]) {
            ++ans;
            if (tp[i] != i) {
              ans += Chk(tp[i]);
              ans += S::Query(dfn[tp[i]] + 1, dfn[i]);
            }
          }
        }
        
        scanf("%d", &nq);
        for (int u, v; nq--; ) {
          scanf("%d%d", &u, &v);
          Flip(u);
          Flip(v);
          printf("%d
    ", (n == 1)? 0 : n - ans + 1);
        }
        
        // remember to clear up
        clk = 0;
        for (int i = 1; i <= n; ++i) {
          g[i].clear();
          so[i] = tp[i] = nat[i] = cnt[i][0] = cnt[i][1] = 0;
        }
      }
      
      return 0;
    }
    View Code

    Sonya and Queries

    (被象飞了,写了4个小时)

    我们暂且不考虑操作$7$。如果只有前六个操作,大概就是要实现一个数据结构,支持:1,在原树的基础上$link/cut$;2,整个联通块加上一个正数;3,整个联通块赋值为$0$;4,联通块求和;5,单点加,单点查询。由于只有子树的相关操作,所以这些都可以用$ETT$直接解决,也十分好写,只要实现一棵平衡树维护双括号序,$link/cut$时只要$merge/split$就行了。

    操作$7$,其要求所有有值的联通块构成的虚树的边数(也就是点数)。考虑如果我们现在有一棵以联通块为点构成的树$T'$,记$cnt_x$表示$x$的子树里有值的点的个数,令$tot$为$T'$点的个数,则要求的虚树的点数为:$tot - sumlimits_{i = 1}^{tot}[cnt_i = 0] - sumlimits_{i = 1}^{tot}[cnt_i = cnt_{root}] + 1$。如果某一个点是$0$是$1$的状态改变了,相当于对该点的祖先链的$cnt$执行$+1$或$-1$,实现起来简单点的话可以直接轻重链剖分,用线段树维护树链,并且记录区间内最大值及其个数,最小值及其个数,$sumlimits_{i = 1}^{tot}[cnt_i = 0]$就是全局最小值的个数(如果最小值是$0$的话),$sumlimits_{i = 1}^{tot}[cnt_i = cnt_{root}]$就是全局最大值的个数。回到原树上,我们把每个联通块的贡献算到该联通块的根上,即只用其根来标志这个联通块,每个$1$~$6$操作后可能会改掉某个联通块是否有值的状态,也可能会增加或取消某个用于标记联通块的点,这些都扔到线段树上改改就行了。

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

    #include <bits/stdc++.h>
    
    using namespace std;
    
    const int N = 2.5e5 + 5;
    const int INF = 1e9 + 7;
    const pair<int, int> PINF = pair<int, int>(INF, 0);
    const pair<int, int> PFNI = pair<int, int>(-INF, 0);
    
    int n, nq, tot, clk;
    int tv[N * 2], bel[N], fw[N], valsub[N], ival[N];
    vector<int> g[N];
    int fa[N], si[N], so[N], tp[N], dep[N], dfn[N], li[N];
    bool usd[N];
    char av[N];
    
    namespace S {
      struct Node {
        pair<int, int> mn, mx;
        int tagadd, cnt;
      } node[N * 4];
    
      pair<int, int> Comb_min(pair<int, int> a, pair<int, int> b) {
        if (a.first < b.first) {
          return a;
        } else if (a.first > b.first) {
          return b;
        } else {
          return pair<int, int>(a.first, a.second + b.second);
        }
      }
    
      pair<int, int> Comb_max(pair<int, int> a, pair<int, int> b) {
        if (a.first > b.first) {
          return a;
        } else if (a.first < b.first) {
          return b;
        } else {
          return pair<int, int>(a.first, a.second + b.second);
        }
      }
      
      void Up(int t) {
        node[t].mn = Comb_min(node[t << 1].mn, node[t << 1 | 1].mn);
        node[t].mx = Comb_max(node[t << 1].mx, node[t << 1 | 1].mx);
      }
    
      void Uadd(int t, int _v) {
        Node &nw = node[t];
        nw.tagadd += _v;
        nw.cnt += _v;
        nw.mn.first += _v;
        nw.mx.first += _v;
      }
    
      void Down(int t) {
        if (node[t].tagadd) {
          Uadd(t << 1, node[t].tagadd);
          Uadd(t << 1 | 1, node[t].tagadd);
          node[t].tagadd = 0;
        }
      }
      
      void Build(int t, int l, int r) {
        if (l == r) {
          node[t].cnt = valsub[li[l]];
          node[t].mn = usd[li[l]]? pair<int, int>(node[t].cnt, 1) : PINF;
          node[t].mx = usd[li[l]]? pair<int, int>(node[t].cnt, 1) : PFNI;
          return;
        }
        int md = (l + r) >> 1;
        Build(t << 1, l, md);
        Build(t << 1 | 1, md + 1, r);
        Up(t);
      }
      
      void Modify(int t, int l, int r, int L, int R, int _v) {
        if (L <= l && r <= R) {
          Uadd(t, _v);
          return;
        }
        int md = (l + r) >> 1;
        Down(t);
        if (L <= md) Modify(t << 1, l, md, L, R, _v);
        if (R > md) Modify(t << 1 | 1, md + 1, r, L, R, _v);
        Up(t);
      }
    
      void Change_usd(int t, int l, int r, int x) {
        if (l == r) {
          node[t].mn = usd[li[l]]? pair<int, int>(node[t].cnt, 1) : PINF;
          node[t].mx = usd[li[l]]? pair<int, int>(node[t].cnt, 1) : PFNI;
          return;
        }
        int md = (l + r) >> 1;
        Down(t);
        if (x <= md) Change_usd(t << 1, l, md, x);
        else Change_usd(t << 1 | 1, md + 1, r, x);
        Up(t);
      }
      
      pair<int, int> Query_min(int t, int l, int r, int L, int R) {
        if (L <= l && r <= R) {
          return node[t].mn;
        }
        int md = (l + r) >> 1;
        Down(t);
        pair<int, int> re = PINF;
        if (L <= md) re = Comb_min(re, Query_min(t << 1, l, md, L, R));
        if (R > md) re = Comb_min(re, Query_min(t << 1 | 1, md + 1, r, L, R));
        return re;
      }
    
      pair<int, int> Query_max(int t, int l, int r, int L, int R) {
        if (L <= l && r <= R) {
          return node[t].mx;
        }
        int md = (l + r) >> 1;
        Down(t);
        pair<int, int> re = PFNI;
        if (L <= md) re = Comb_max(re, Query_max(t << 1, l, md, L, R));
        if (R > md) re = Comb_max(re, Query_max(t << 1 | 1, md + 1, r, L, R));
        return re;
      }
      
    }
    
    
    int li2[N * 2], st[N * 2], ed[N * 2], clk2;
    
    namespace T {
      struct Node {
        int lc, rc, p, sz, rnd, tagcov;
        long long val, sum, tagadd;
      } node[N * 2];
    
      void Up(int t) {
        node[t].sum = node[t].val + node[node[t].lc].sum + node[node[t].rc].sum;
        node[t].sz = 1 + node[node[t].lc].sz + node[node[t].rc].sz;
      }
    
      void Ucov(int t) {
        Node &nw = node[t];
        nw.val = nw.sum = nw.tagadd = 0;
        nw.tagcov = 1;
      }
    
      void Uadd(int t, long long _v) {
        Node &nw = node[t];
        nw.val += _v;
        nw.tagadd += _v;
        nw.sum += _v * nw.sz;
      }
      
      void Down(int t) {
        Node &nw = node[t];
        if (nw.tagcov) {
          if (nw.lc) Ucov(nw.lc);
          if (nw.rc) Ucov(nw.rc);
          nw.tagcov = 0;
        }
        if (nw.tagadd) {
          if (nw.lc) Uadd(nw.lc, nw.tagadd);
          if (nw.rc) Uadd(nw.rc, nw.tagadd);
          nw.tagadd = 0;
        }
      }
    
      void Split(int t, int k, int &x, int &y) {
        if (!k) {
          x = 0;
          y = t;
          return;
        }
        Down(t);
        if (k <= node[node[t].lc].sz) {
          y = t;
          node[node[t].lc].p = 0;
          Split(node[t].lc, k, x, node[t].lc);
          node[node[t].lc].p = t;
        } else {
          x = t;
          node[node[t].rc].p = 0;
          Split(node[t].rc, k - node[node[t].lc].sz - 1, node[t].rc, y);
          node[node[t].rc].p = t;
        }
        Up(t);
      }
    
      int Merge(int x, int y) {
        if (!x || !y) {
          return x | y;
        }
        if (node[x].rnd < node[y].rnd) {
          Down(x);
          node[x].rc = Merge(node[x].rc, y);
          node[node[x].rc].p = x;
          Up(x);
          return x;
        } else {
          Down(y);
          node[y].lc = Merge(x, node[y].lc);
          node[node[y].lc].p = y;
          Up(y);
          return y;
        }
      }
    
      int Rank(int x) {
        int ret = node[node[x].lc].sz;
        while (node[x].p) {
          if (x == node[node[x].p].rc) {
            x = node[x].p;
            ret += node[node[x].lc].sz + 1;
          } else {
            x = node[x].p;
          }
        }
        return ret + 1;
      }
    
      void Roll(int x) {
        if (node[x].p) {
          Roll(node[x].p);
        }
        Down(x);
      }
      
      void Wish(int x, long long _v) {
        Roll(x);
        node[x].val = _v;
        while (x) {
          Up(x);
          x = node[x].p;
        }
      }
    
      long long Thanks(int x) {
        Roll(x);
        return node[x].val;
      }
      
      int Find_root(int x) {
        while (node[x].p) {
          x = node[x].p;
        }
        return x;
      }
    
      int Gen(int x) {
        while (node[x].lc) {
          x = node[x].lc;
        }
        return x;
      }
      
    }
    
    
    void Dfs0(int x) {
      si[x] = 1;
      valsub[x] = ival[x] > 0;
      for (int i = 0; i < g[x].size(); ++i) {
        int e = g[x][i], v = tv[e];
        if (v == fa[x]) continue;
        fa[v] = x;
        dep[v] = dep[x] + 1;
        bel[e / 2] = v;
        fw[v] = e / 2;
        Dfs0(v);
        si[x] += si[v];
        if (si[v] > si[so[x]]) so[x] = v;
        valsub[x] += valsub[v];
      }
    }
    
    void Dfs1(int x, int gr) {
      dfn[x] = ++clk;
      li[clk] = x;
      
      st[x] = ++clk2;
      li2[clk2] = x;
      T::node[clk2] = (T::Node){ 0, 0, 0, 1, rand(), 0, ival[x], ival[x], 0 };
      
      tp[x] = gr;
      if (so[x]) {
        Dfs1(so[x], gr);
      }
      for (int i = 0; i < g[x].size(); ++i) {
        int e = g[x][i], v = tv[e];
        if (v != fa[x] && v != so[x]) {
          Dfs1(v, v);
        }
      }
    
      ed[x] = ++clk2;
      li2[clk2] = x;
      T::node[clk2] = (T::Node){ 0, 0, 0, 1, rand(), 0, ival[x], ival[x], 0 };
      T::Merge(st[x], ed[x]);
    }
    
    void Chain_update(int x, int _v) {
      while (x) {
        S::Modify(1, 1, n, dfn[tp[x]], dfn[x], _v);
        x = fa[tp[x]];
      }
    }
    
    void Cut_from_father(int x) {
      int l = st[x], r = ed[x];
      int rkl = T::Rank(l), rkr = T::Rank(r);
      int rt = T::Find_root(l);
      long long lsv = T::node[rt].sum;
      static int a, b, c;
      T::Split(rt, rkr, b, c);
      T::Split(b, rkl - 1, a, b);
      rt = T::Merge(a, c);
      usd[x] = 1;
      ++tot;
      S::Change_usd(1, 1, n, dfn[x]);
      if (T::node[b].sum > 0) {
        Chain_update(x, 1);
      }
      if (lsv > 0 && T::node[rt].sum == 0) {
        int ge = li2[T::Gen(rt)];
        Chain_update(ge, -1);
      }
    }
    
    void Link_to_father(int x) {
      int y = fa[x];
      int rkl = T::Rank(st[y]);
      int rt = T::Find_root(st[y]);
      long long lsv = T::node[rt].sum;
      static int a, b, c;
      T::Split(rt, rkl, a, c);
      b = T::Find_root(st[x]);
      if (T::node[b].sum > 0) {
        Chain_update(x, -1);
      }
      usd[x] = 0;
      --tot;
      S::Change_usd(1, 1, n, dfn[x]);
      rt = T::Merge(T::Merge(a, b), c);
      if (lsv == 0 && T::node[rt].sum > 0) {
        int ge = li2[T::Gen(rt)];
        Chain_update(ge, 1);
      }
    }
    
    int main() {
      scanf("%*d%d%d", &n, &nq);
      tot = n;
      for (int i = 1, x, y; i < n; ++i) {
        scanf("%d%d", &x, &y);
        tv[i * 2] = y;
        g[x].push_back(i * 2);
        tv[i * 2 + 1] = x;
        g[y].push_back(i * 2 + 1);
      }
      
      scanf("%s", av + 1);
      for (int i = 1; i <= n; ++i) {
        scanf("%d", &ival[i]);
        usd[i] = 1;
      }
      
      Dfs0(1);
      Dfs1(1, 1);
      S::Build(1, 1, n);
      
      for (int i = 1; i < n; ++i) {
        av[i] -= '0';
        if (av[i] == 0) {
          Link_to_father(bel[i]);
        }
      }
      
      for (int ty, x, y; nq--; ) {
        scanf("%d", &ty);
        if (ty != 7) {
          scanf("%d", &x);
        }
    
        if (ty == 1) {
          av[x] ^= 1;
          if (av[x] == 1) {
            Cut_from_father(bel[x]);
          } else {
            Link_to_father(bel[x]);
          }
        }
    
        if (ty == 2) {
          scanf("%d", &y);
          if (y != 0) {
            int rt = T::Find_root(st[x]);
            long long lsv = T::node[rt].sum;
            T::Uadd(rt, y);
            if (!lsv) {
              int ge = li2[T::Gen(rt)];
              Chain_update(ge, 1);
            }
          }
        }
    
        if (ty == 3) {
          int rt = T::Find_root(st[x]);
          long long sum = T::node[rt].sum / 2;
          T::Ucov(rt);
          T::Wish(st[x], sum);
          T::Wish(ed[x], sum);
        }
    
        if (ty == 4) {
          printf("%lld
    ", T::Thanks(st[x]));
        }
    
        if (ty == 5) {
          int rt = T::Find_root(st[x]);
          long long sum = T::node[rt].sum;
          printf("%lld
    ", sum / 2);
        }
    
        if (ty == 6) {
          int rt = T::Find_root(st[x]);
          long long lsv = T::node[rt].sum;
          T::Ucov(rt);
          if (lsv) {
            int ge = li2[T::Gen(rt)];
            Chain_update(ge, -1);
          }
        }
    
        if (ty == 7) {
          int res = tot;
          res -= S::Query_max(1, 1, n, 1, n).second - 1;
          pair<int, int> mim = S::Query_min(1, 1, n, 1, n);
          if (mim.first == 0) {
            res -= mim.second;
          }
          printf("%d
    ", max(0, res - 1));
        }
        
        if (ty == 4 || ty == 5 || ty== 7) {
          fflush(stdout);
        }
      }
      
      return 0;
    }
    View Code
  • 相关阅读:
    webpack learn2-vue的jsx写法和postcss 1
    浏览器缓存旧的js文件或css文件导致没出现预期效果
    webpack learn1-webpack-dev-server的配置和使用3
    Python正课60 —— configparser模块
    Python正课59 —— json与pickle模块
    Python正课58 —— 小说阅读项目 初级
    Python正课57 —— ATM+购物车 前戏
    Python正课56 —— shutil模块
    Python正课55 —— sys模块
    Python正课54 —— os模块
  • 原文地址:https://www.cnblogs.com/Dance-Of-Faith/p/10712425.html
Copyright © 2011-2022 走看看