• P3660 [USACO17FEB]Why Did the Cow Cross the Road III G


    Link

    题意

    给定长度为 (2N) 的序列,(1~N) 各处现过 (2) 次,i第一次出现位置记为(ai),第二次记为(bi),求满足(ai<aj<bi<bj)的对数.

    转化一下题意:求 (a_i - b_i) 中出现次数为 (1) 的个数。

    既然数据范围那么小,直接上莫队。

    先预处理出每个数第一次出现以及第二次出现的位置。

    然后就变成了我们熟悉的区间问题。就可以套用莫队的板子啦,

    但最后答案要除以 二,因为 ((x,y)) 这两个数对,你在 (x) 这个位置会算一遍,在 (y) 这个位置同样也会被算一遍。

    可这个却只能算一遍,所以最后答案要除以二。

    计算移动指针的贡献的时候,不要忘记计算移动前和移动后对现在答案的影响。

    具体的细节可以看代码:

    Code

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    const int N = 1e5+10;
    int n,m,ans,tmp,l,r,block,x;
    int pos[N],fir[N],sec[N],cnt[N],a[N];
    struct node
    {
        int l,r,id;
    }q[N];
    inline int read()
    {
        int s = 0,w = 1; char ch = getchar();
        while(ch < '0' || ch > '9'){if(ch == '-') w = -1; ch = getchar();}
        while(ch >= '0' && ch <= '9'){s = s * 10 + ch - '0'; ch = getchar();}
        return s * w;
    }
    bool comp(node a,node b)
    {
        if(pos[a.l] == pos[b.l]) return a.r < b.r;
        return pos[a.l] < pos[b.l];
    }
    void add(int x)
    {
    	if(cnt[a[x]] == 0) tmp++;//如果说当前这个数在这段区间第一次出现,对答案的贡献加1
        cnt[a[x]]++;
        if(cnt[a[x]] == 2) tmp--;//出现两次对答案没有贡献
    }
    void del(int x)
    {
        if(cnt[a[x]] == 2) tmp++;//出现次数变为一次,就会对答案的贡献加1
        cnt[a[x]]--;
        if(cnt[a[x]] == 0) tmp--;//没有出现,对答案的贡献就会变为0
    }
    int main()
    {
        n = read(); block = sqrt(2 * n);
        for(int i = 1; i <= 2 * n; i++)
        {
            a[i] = read();
            if(fir[a[i]] == 0) fir[a[i]] = i;//求一个数第一次以及第二次出现的位置
            else sec[a[i]] = i;
        }
        for(int i = 1; i <= 2 * n; i++) pos[i] = (i - 1) / block + 1;//分块预处理,注意是对序列分块
        for(int i = 1; i <= n; i++)
        {
            q[i].l = fir[i];
            q[i].r = sec[i];
            q[i].id = i;
        }
        sort(q+1,q+n+1,comp);
        l = 1, r = 0, tmp = 0;
        for(int i = 1; i <= n; i++)//莫队板子
        {
            while(l < q[i].l) del(l++);
            while(l > q[i].l) add(--l);
            while(r < q[i].r) add(++r);
            while(r > q[i].r) del(r--);
            ans += tmp;
        }
        printf("%d
    ",ans/2);//最后不要忘记除以二
        return 0;
    }
    
  • 相关阅读:
    设计师用的几个网站
    微信小程序开发框架
    数据模型
    数据库系统
    大话设计模式读书笔记(一)
    关于数据统计时的效率
    orcale同一条语句运行速度差异问题
    使用plspl创建orcale作业
    正则表达式(一)
    oracle游标小试
  • 原文地址:https://www.cnblogs.com/genshy/p/13654338.html
Copyright © 2020-2023  润新知