CSU 2070 Seating Chart(线段树求逆序数)

CSU 2070 Seating Chart

题意

​ 给出一个序列,求第二个序列的逆序数。

解题思路

  如果直接暴力求解,肯定会TLE。队友是用归并排序过的,我重新写了遍线段树,算法复杂度是O(nlogn)。

  对于使用线段树求逆序数,方法如下。

  对于求逆序数,我们只需要求出每个数字的前面有几个比他大的数,最后再把这些数加起来就是逆序数。有了这样的思路,我们就可以通过一边构造线段树,一边通过查询求和,从而得到逆序数。至于如何构造这个线段树,首先我们先构建一个空树,然后我们再对序列里面的每一个元素进行遍历。最下面一层最终构造出来的是1-n这个序列。例如当前遍历到arr[i]节点,那么我们就将它构造在其值对应的节点,然后再更新所有包含它的区间。然后就是查找,我们只需要查找[arr[i]+1,n]这个区间有多少元素就行了,因为当前树上有的是arr[i]之前的元素,查询这个区间我们就知道到底有几个比它大。最后求得的查询的和就是逆序数。

代码

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<map>
using namespace std;
const int maxn = 1e5+5;

int tree[maxn<<2];
map<string,int> m;
void pushup(int rt)
{
    tree[rt]=tree[rt<<1]+tree[rt<<1|1];
}
void update(int id,int l,int r,int rt)
{
    if(l==r)
    {
        tree[rt]=1;
        return;
    }
    int m=(l+r)>>1;
    if(id<=m) update(id,l,m,rt<<1);
    else update(id,m+1,r,rt<<1|1);
    pushup(rt);
}
long long query(int L,int R,int l,int r,int rt)
{
    if(L<=l&&R>=r) return tree[rt];
    int m=(l+r)>>1;
    long long ans=0;
    if(L<=m) ans+=query(L,R,l,m,rt<<1);
    if(R> m) ans+=query(L,R,m+1,r,rt<<1|1);
    return ans;
}
int main()
{
//    freopen("in.txt","r",stdin);
    int n;
    while(cin>>n&&n)
    {
        string str;
        memset(tree,0,sizeof(tree));
        for(int i=1; i<=n; i++)
        {
            cin>>str;
            m[str]=i;
        }
        long long ans=0;
        for(int i=1; i<=n; i++)
        {
            cin>>str;
            update(m[str],1,n,1);
            ans+=query(m[str]+1,n,1,n,1);
        }
        cout<<ans<<endl;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_36258516/article/details/79996684