zoukankan      html  css  js  c++  java
  • 打卡2

    XOR and Favorite Number

    这个题能改变成加法。

    第三个while始终觉得区间变长了,看了一下午还是很难理解。

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 1e5 + 50;
    typedef long long ll;
    int a[maxn];
    struct node
    {
        int l, r;
        int block;
        int id;
    };
    node q[maxn];
    bool cmp(node A, node B)
    {
        if(A.block == B.block) return A.r < B.r;
        else return A.l < B.l;
    }
    ll out[maxn];
    int sum[maxn];
    ll cnt[1 << 20];
    int main()
    {
        int n, m, k; scanf("%d %d %d", &n, &m, &k);
        for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
        for(int i = 1; i <= n; i++)
        {
            sum[i] = sum[i - 1] ^ a[i];
        }
        int block = sqrt(n);
        for(int i = 1; i <= m; i++)
        {
            scanf("%d %d", &q[i].l, &q[i].r);
            q[i].block = q[i].l / block;
            q[i].id = i;
        }
        sort(q + 1, q + m + 1, cmp);
        memset(cnt, 0, sizeof(cnt));
        int l = 1, r = 0;
        ll ans = 0;
        cnt[0]++;
        for(int i = 1; i <= m; i++)
        {
            while(r < q[i].r)
            {
                r++;
                ans += cnt[sum[r] ^ k];
               // printf("%d %d %d
    ", sum[r], sum[r] ^ k, cnt[sum[r] ^ k]);
                cnt[sum[r]]++;
            }
           //printf("%d
    ", ans);
            while(r > q[i].r)
            {
                cnt[sum[r]]--; ///先把我自己去掉,以免产生影响
                ans -= cnt[sum[r] ^ k];
                r--;
            }
            while(l < q[i].l)
            {
                cnt[sum[l - 1]]--; ///也是先把我自己去掉
                ans -= cnt[sum[l - 1] ^ k];
                l++;
            }
            while(l > q[i].l)
            {
                l--;
                ans += cnt[sum[l - 1] ^ k];
                cnt[sum[l - 1]]++;
            }
            out[q[i].id] = (ans >= 0LL ? ans : 0LL);
        }
        for(int i = 1; i <= m; i++)
        {
            printf("%lld
    ", out[i]);
        }
        return 0;
    }
    
    
    /*
    6 1 3
    1 2 1 1 0 3
    3 4
    */
    Code

     

    CodeForces - 294E

    今天各种保研事情,没做上,明天继续补。

    ---------------------------------------------------

    首先对于这颗树,如果我们去掉的是$u->v$这条边,那么我们考虑最优解是:

    $sum=(u的子树内任意两点的和)+(v的子树内任意两点的和)+(u的子树内,所有点到某个点距离和的最小值 imes v的子树个数)+(v的子树内,所有点到某个点距离和的最小值 imes u的子树个数)+(u的子树个数 imes v的子树个数 imes 这条路径长度)$.

    一个$O(n^3)$的做法:枚举删掉的边,还有枚举补上的边,再跑一遍。

     在找新边的时候,前两项是定值,我们只需要计算后三项的最小值,要统计每个点到它子树的距离,然后$O(n^2)$枚举即可。

    那么现在我们要求的就是,每个点它子树内的任意两点和,每个点到它子树的距离, 每个点的子树个数。

    每个点到它子树内的任意两点和,枚举边的贡献即可,顺便计算点总数。

    每个点的子树内,所有点到某个点距离和的最小值,先求以根的和,dfs处理的时候再转换一下。

    (看网上都说 求某颗树内所有点到某个点距离和的最小值是经典套路……)

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int maxn = 5e3 + 5;
    struct node
    {
        int v, w;
    };
    vector<node> g[maxn];
    int u[maxn], v[maxn], w[maxn];
    int son[maxn];
    ll d[maxn]; ///树内所有点到某个点的距离和
    void dfs1(int u, int fa)
    {
        son[u] = 0;
        son[u]++;
        for(int i = 0; i < (int)g[u].size(); i++)
        {
            int v = g[u][i].v;
            if(v == fa) continue;
            dfs1(v, u);
            son[u] += son[v];
        }
    }
    int tot = 0;
    void dfs2(int u, int fa, ll & sum1)
    {
        d[u] = 0;
        for(int i = 0; i < (int)g[u].size(); i++)
        {
            int v = g[u][i].v;
            if(v == fa) continue;
            dfs2(v, u, sum1);
            sum1 += (ll)son[v] * (tot - son[v]) * g[u][i].w; ///任意两点之间的距离和
            d[u] += d[v] + (ll)son[v] * g[u][i].w;
        }
       // printf("%d %I64d
    ", u, d[u]);
    }
    ll minv = 0;
    void dfs3(int u, int fa)
    {
        minv = min(minv, d[u]);
        for(int i = 0; i < (int)g[u].size(); i++)
        {
            int v = g[u][i].v;
            if(v == fa) continue;
            d[v] = d[v] + (d[u] - d[v] - (ll)son[v] * g[u][i].w) + (ll)(son[u] - son[v]) * g[u][i].w;
            son[v] = son[u];
            dfs3(v, u);
        }
    }
    int main()
    {
        int n; scanf("%d", &n);
        for(int i = 1; i <= n - 1; i++)
        {
            scanf("%d %d %d", &u[i], &v[i], &w[i]);
            g[u[i]].push_back({v[i], w[i]});
            g[v[i]].push_back({u[i], w[i]});
        }
        ll ans = 1e18;
        for(int i = 1; i <= n - 1; i++)
        {
            ll tmp = 0;
            dfs1(u[i], v[i]);
            ll sum1 = 0;
            tot = son[u[i]];
            dfs2(u[i], v[i], sum1);
            tmp += sum1;
            minv = 1e18;
            dfs3(u[i], v[i]);
            int cntu = son[u[i]];
            dfs1(v[i], u[i]);
            sum1 = 0;
            tot = son[v[i]];
            dfs2(v[i], u[i], sum1);
            tmp += sum1;
            tmp += minv * son[v[i]];
            minv = 1e18;
            dfs3(v[i], u[i]);
            tmp += minv * cntu;
            tmp += (ll)cntu * son[v[i]] * w[i];
            //printf("%I64d
    ", tmp);
            ans = min(ans, tmp);
        }
        printf("%I64d
    ", ans);
        return 0;
    }
    Code

    写的有点乱,再整理一下。

  • 相关阅读:
    sys模块
    反射
    动态导入模块
    类的静态属性
    多态
    继承
    组合
    linux系统各个子目录的内容
    mysql安装
    Docker 数据卷操作
  • 原文地址:https://www.cnblogs.com/littlepear/p/9588162.html
Copyright © 2011-2022 走看看