• USACO 2017 FEB Platinum mincross 可持久化线段树


      题意

        上下有两个位置分别对应的序列A、B,长度为n,两序列为n的一个排列。当Ai == Bj时,上下会连一条边。你可以选择序列A或者序列B进行旋转任意K步,如 3 4 1 5 2 旋转两步为 5 2 3 4 1。求旋转后最小的相交的线段的对数。

      很暴力的就做了这一题,当选择A进行旋转时,A序列翻倍,然后建一棵主席树,记录点Bi的度数,为了更新用(其实可以O(1)更新),然后长度为n的区间扫一遍。

      B亦同。

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <string>
    #include <algorithm>
    #include <iostream>
    
    using namespace std;
    
    typedef long long LL;
    const int maxn = 100005*2;
    int n, a[maxn], b[maxn], to[maxn];
    struct Tree
    {
        int sum[maxn*40], ls[maxn*40], rs[maxn*40], cnt;
        Tree()
        {
            cnt = 0;
        }
        void pushup(int rt)
        {
            sum[rt] = sum[ls[rt]]+sum[rs[rt]];    
        }    
        void update(int las_rt, int rt, int l, int r, int p, int d)
        {
            if (l == r)
            {
                sum[rt] = sum[las_rt]+d;
                return ;
            }
            int mid = (l+r)>>1;
            if (p <= mid)
            {
                ls[rt] = ++cnt, rs[rt] = rs[las_rt];
                update(ls[las_rt], ls[rt], l, mid, p, d);
            }
            else
            {
                ls[rt] = ls[las_rt], rs[rt] = ++cnt;
                update(rs[las_rt], rs[rt], mid+1, r, p, d);
            }
            pushup(rt);
        }
        int query(int rt_1, int rt_2, int l, int r, int L, int R)
        {
            if (L <= l && r <= R)
                return sum[rt_2]-sum[rt_1];
            int mid = (l+r)>>1, ret = 0;
            if (L <= mid)
                ret += query(ls[rt_1], ls[rt_2], l, mid, L, R);
            if (R > mid)
                ret += query(rs[rt_1], rs[rt_2], mid+1, r, L, R);
            return ret;
        }
    }T1, T2;
    int root1[maxn], root2[maxn];
    
    int main()
    {
        freopen("mincross.in", "r", stdin);
        freopen("mincross.out", "w", stdout);
        scanf("%d", &n);
        for (int i = 1; i <= n; ++i)
            scanf("%d", &a[i]), a[n+i] = a[i];
        for (int i = 1; i <= n; ++i)
            scanf("%d", &b[i]), b[n+i] = b[i];
    //part 1
        for (int i = 1; i <= n; ++i)
            to[b[i]] = i;
        root1[1] = ++T1.cnt;
        T1.update(0, root1[1], 1, n, to[a[1]], 1);
        for (int i = 2; i <= 2*n; ++i)
        {
            root1[i] = ++T1.cnt;
            T1.update(root1[i-1], root1[i], 1, n, to[a[i]], 1);
        }
        LL now_sum = 0, ans;
        for (int i = 1; i <= n; ++i)
            if (to[a[i]]+1 <= n)
                now_sum += T1.query(0, root1[i], 1, n, to[a[i]]+1, n);
        ans = now_sum;
        for (int i = n+1; i <= 2*n; ++i)
        {
            int temp = 0;
            if (to[a[i]]-1 >= 1)
                temp = T1.query(root1[i-n], root1[i-1], 1, n, 1, to[a[i]]-1);
            now_sum -= temp, now_sum += (n-temp-1);
            ans = min(ans, now_sum);
        }
    //part 2
        for (int i = 1; i <= n; ++i)
            to[a[i]] = i;
        root2[1] = ++T2.cnt;
        T2.update(0, root2[1], 1, n, to[b[1]], 1);
        for (int i = 2; i <= 2*n; ++i)
        {
            root2[i] = ++T2.cnt;
            T2.update(root2[i-1], root2[i], 1, n, to[b[i]], 1);
        }
        now_sum = 0;
        for (int i = 1; i <= n; ++i)
            if (to[b[i]]+1 <= n)
                now_sum += T2.query(0, root2[i], 1, n, to[b[i]]+1, n);
        for (int i = n+1; i <= 2*n; ++i)
        {
            int temp = 0;
            if (to[b[i]]-1 >= 1)
                temp = T2.query(root2[i-n], root2[i-1], 1, n, 1, to[b[i]]-1);
            now_sum -= temp, now_sum += (n-temp-1);
            ans = min(ans, now_sum);
        }
        cout <<ans <<endl;
        return 0;
    }
  • 相关阅读:
    闯荡Linux帝国:nginx的创业故事
    一个HTTP数据包的奇幻之旅
    远去的传说:安全软件群雄混战史
    默认浏览器争霸传奇
    浏览器主页锁定之战——IE:我太难了
    产品vs程序员:你知道www是怎么来的吗?
    手把手教你从零开始搭建SpringBoot后端项目框架
    使用IntelliJ IDEA新建Java Web后端resfulAPI模板
    如何正确的在项目中接入微信JS-SDK
    html2canvas关于图片不能正常截取
  • 原文地址:https://www.cnblogs.com/-ZZB-/p/6403411.html
Copyright © 2020-2023  润新知