• 电路(权限题)


    题意:给定树和长为m的序列。对于每个长为偶数的子串,你都要在树上将这些点以最小代价两两匹配。求总代价。

    解:考虑贪心匹配。如果一个子树内有奇数个备选点,那么这个边的贡献 + 1。

    考虑每条边的贡献,只需知道每条边的子树这些点,有多少个长为偶数的区间把它们包含了奇数次。

    发现可以维护奇偶位置前缀和的奇偶性个数。然后乘一下。注意这里的前缀和,开头是以l为下标1,而不是以l为下标l,且空节点的前缀和全部为0,要注意。

    然后用线段树合并维护这些前缀和即可,对每条边统计答案。

      1 #include <bits/stdc++.h>
      2 
      3 typedef long long LL;
      4 
      5 const int N = 600010, MO = 998244353;
      6 
      7 struct Edge {
      8     int nex, v, len;
      9 }edge[N << 1]; int tp;
     10 
     11 int n, e[N], a[N], ans, rt[N], m;
     12 
     13 namespace seg {
     14     const int V = 15000000;
     15     int ls[V], rs[V], sum[2][2][V], siz[V], sl[2][2], sr[2][2], tot;
     16     inline void pushup(int l, int r, int o) {
     17         int mid = (l + r) >> 1, L = ls[o], R = rs[o], len = mid - l + 1, len2 = r - mid;
     18         int f = (mid - l + 1) & 1, f2 = siz[L] & 1;
     19 
     20         siz[o] = siz[L] + siz[R];
     21 
     22         if(L) {
     23             sl[0][0] = sum[0][0][L];
     24             sl[0][1] = sum[0][1][L];
     25             sl[1][0] = sum[1][0][L];
     26             sl[1][1] = sum[1][1][L];
     27         }
     28         else {
     29             sl[0][0] = len >> 1;
     30             sl[0][1] = 0;
     31             sl[1][0] = (len + 1) >> 1;
     32             sl[1][1] = 0;
     33         }
     34 
     35         if(R) {
     36             sr[0][0] = sum[0][0][R];
     37             sr[0][1] = sum[0][1][R];
     38             sr[1][0] = sum[1][0][R];
     39             sr[1][1] = sum[1][1][R];
     40         }
     41         else {
     42             sr[0][0] = len2 >> 1;
     43             sr[0][1] = 0;
     44             sr[1][0] = (len2 + 1) >> 1;
     45             sr[1][1] = 0;
     46         }
     47 
     48         sum[0][0][o] = sl[0][0] + sr[f][f2];
     49         sum[0][1][o] = sl[0][1] + sr[f][f2 ^ 1];
     50         sum[1][0][o] = sl[1][0] + sr[f ^ 1][f2];
     51         sum[1][1][o] = sl[1][1] + sr[f ^ 1][f2 ^ 1];
     52         return;
     53     }
     54     void insert(int p, int l, int r, int &o) {
     55         if(!o) {
     56             o = ++tot;
     57         }
     58         if(l == r) {
     59             siz[o] = sum[1][1][o] = 1;
     60             return;
     61         }
     62         int mid = (l + r) >> 1;
     63         if(p <= mid) {
     64             insert(p, l, mid, ls[o]);
     65         }
     66         else {
     67             insert(p, mid + 1, r, rs[o]);
     68         }
     69         pushup(l, r, o);
     70         return;
     71     }
     72     int merge(int x, int y, int l, int r) {
     73         if(!x || !y) {
     74             return x | y;
     75         }
     76         int mid = (l + r) >> 1;
     77         ls[x] = merge(ls[x], ls[y], l, mid);
     78         rs[x] = merge(rs[x], rs[y], mid + 1, r);
     79         pushup(l, r, x);
     80         return x;
     81     }
     82 
     83     inline void calc(int x, int v) {
     84         int temp = (LL)(sum[0][0][x] + 1) * sum[0][1][x] % MO;
     85         //printf("temp = %d 
    ", temp);
     86         temp = (temp + (LL)sum[1][0][x] * sum[1][1][x] % MO) % MO;
     87         //printf("temp += %d * %d
    ", sum[1][0][x], sum[1][1][x]);
     88         ans = (ans + (LL)temp * v % MO) % MO;
     89         //printf("ans += %d * %d 
    ", temp, v);
     90         return;
     91     }
     92 }
     93 
     94 inline void add(int x, int y, int z) {
     95     edge[++tp].v = y;
     96     edge[tp].len = z;
     97     edge[tp].nex = e[x];
     98     e[x] = tp;
     99     return;
    100 }
    101 
    102 void DFS(int x, int fa, int v) {
    103     for(int i = e[x]; i; i = edge[i].nex) {
    104         int y = edge[i].v;
    105         if(y == fa) {
    106             continue;
    107         }
    108         DFS(y, x, edge[i].len);
    109         rt[x] = seg::merge(rt[x], rt[y], 1, m);
    110     }
    111     //printf("x = %d 
    ", x);
    112     seg::calc(rt[x], v);
    113     return;
    114 }
    115 
    116 int main() {
    117 
    118     freopen("electricity.in", "r", stdin);
    119     freopen("electricity.out", "w", stdout);
    120 
    121     scanf("%d%d", &n, &m);
    122     int x, y;
    123     LL z;
    124     for(int i = 1; i < n; i++) {
    125         scanf("%d%d%lld", &x, &y, &z);
    126         add(x, y, z);
    127         add(y, x, z);
    128     }
    129     for(int i = 1; i <= m; i++) {
    130         scanf("%d", &a[i]);
    131         seg::insert(i, 1, m, rt[a[i]]);
    132     }
    133 
    134     DFS(1, 0, 0);
    135 
    136     printf("%d
    ", ans);
    137     return 0;
    138 }
    139 /*
    140 4 4
    141 1 2 1
    142 2 3 2
    143 3 4 1
    144 2 3 1 4
    145 ------------------------
    146 11
    147 */
    AC代码
  • 相关阅读:
    ASP计算周开始和一年有多少周及某年第一周开始日期
    http://www.lancen.net/
    JSP的对象
    两个SQL语句
    sql 分頁
    网页特效制作汇总
    存储过程 解密
    一个计算周次和本周时间范围的代码(c#)
    Java试题
    如何在 VS 2005 里调试 Javascript
  • 原文地址:https://www.cnblogs.com/huyufeifei/p/11101001.html
Copyright © 2020-2023  润新知