HDU 1394 线段树单点更新求逆序数

题意:给出含有0 ~n-1 N个数组成的序列,有N次操作,每次把第一个数放到数列的最后,问这几次数列操作中最小的逆序数的值。

单点更新就可以,每一输入一个数,先查询有几个比这个数大的,再将这个值插入线段树中。

#include <iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 5005
struct  node
{
    int l,r,val;
};
node tree[N<<2];
int num[N];
void build(int root,int l,int r)
{
    tree[root].l=l;
    tree[root].r=r;
    tree[root].val=0;
    if(l==r)
        return;
    int mid=(l+r)>>1;
    build(root<<1,l,mid);
    build(root<<1|1,mid+1,r);
}
void update(int root,int pos,int val)
{
    if(tree[root].l==tree[root].r)
    {
        tree[root].val=val;
        return;
    }
    int mid=(tree[root].l+tree[root].r)>>1;
    if(pos<=mid)
        update(root<<1,pos,val);
    else
        update(root<<1|1,pos,val);
    tree[root].val=tree[root<<1].val+tree[root<<1|1].val;
}
int query(int root,int l,int r)
{
    if(l<=tree[root].l&&r>=tree[root].r)
        return tree[root].val;
    int mid=(tree[root].l+tree[root].r)>>1,ret=0;
    if(l<=mid)
        ret+=query(root<<1,l,r);
    if(r>mid)
        ret+=query(root<<1|1,l,r);
    return ret;
}
int main()
{
    int n;
    while(~scanf("%d",&n))
    {
        build(1,1,n);
        int sum=0;
        for(int i=1; i<=n; i++)
        {
            scanf("%d",&num[i]);
            sum+=query(1,num[i]+1,n-1);
            update(1,num[i],1);
        }
        int ans=1e8;
        for(int i=1; i<=n; i++)
            sum=sum-num[i]+(n-num[i]-1),ans=min(ans,sum);
        printf("%d\n",ans);
    }
    return 0;
}
时间: 2024-11-18 02:33:37

HDU 1394 线段树单点更新求逆序数的相关文章

HDU 1166 线段树单点更新

第一行一个整数T,表示有T组数据.每组数据第一行一个正整数N(N<=50000),表示敌人有N个工兵营地,接下来有N个正整数,第i个正整数ai代表第i个工兵营地里开始时有ai个人(1<=ai<=50).接下来每行有一条命令,命令有4种形式:(1) Add i j,i和j为正整数,表示第i个营地增加j个人(j不超过30)(2)Sub i j ,i和j为正整数,表示第i个营地减少j个人(j不超过30);(3)Query i j ,i和j为正整数,i<=j,表示询问第i到第j个营地的总人

【33】利用归并排序求逆序数对

题目:利用归并排序求解一个数组中的逆序数对 分析: 1. 什么是逆序数对,例如给定数组{7, 5, 6, 4},对于每个数num,如果num之前有多少个数大于num则说明num这个数构成逆序数对有多少个     7有0个,5有1个,6有1个,4有三个,因此数组中总的逆序数对为5. 2. 怎么利用归并排序来求逆序数对呢?    (1)假设数组为{7, 5, 6, 4}    (2)归并排序的递归树如下            (3)求逆序数对是在合并左右两个子序列的时候.在merge函数中,左右子序

归并法求逆序数

求逆序数 时间限制:2000 ms  |  内存限制:65535 KB 难度:5   描述 在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序.一个排列中逆序的总数就称为这个排列的逆序数. 现在,给你一个N个元素的序列,请你判断出它的逆序数是多少. 比如 1 3 2 的逆序数就是1.   输入 第一行输入一个整数T表示测试数据的组数(1<=T<=5) 每组测试数据的每一行是一个整数N表示数列中共有N个元素(2〈=N〈=1000000) 随后的一行共

HDU 1698 线段树成段更新

题意:线段树成段更新,最后查询全区间. #include <iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define maxn 100005 int node[maxn<<2],col[maxn<<2]; void build(int rt,int l,int r) { col[rt]=0,node[rt]

POJ 3468 线段树 区间更新区间查询

题意:给出一段数列,任意区间加上一个整数v,任意区间查询.给出N个数,Q次操作. 线段树的题,延迟指针不更新到底就行了. #include <iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define maxn 100005 long long sum[maxn<<2],col[maxn<<2]; void

Hdu1754-线段树-单点更新

#include<iostream> #include<cstdio> #include<algorithm> using namespace std; #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 const int maxn=200005; int MAX[maxn<<2]; void pushup(int rt) { MAX[rt]=max(MAX[rt<<1],

hdu1394 线段树求最小逆序数

hdu 1394 http://acm.hdu.edu.cn/showproblem.php?pid=1394 用线段树求逆序数,例如要求x的逆序数只需要访问(x+1,n)段有多少个数,就是x的逆序数.还有就是求最小逆序数的时候有个巧妙的想法,当把x放入数组的后面,此时的逆序数应该为x没放入最后面之前的逆序总数加上(n-x)再减去(x-1):sum = sum+(n-x[i])-(x[i]-1). 线段树 #include<cstdio> #include<algorithm> #

[算法系列之二十三]线段树(Interval Tree)

一 背景 在信息学竞赛中,我们经常会碰到一些跟区间有关的问题,比如给一些区 间线段求并区间的长度,或者并区间的个数等等.这些问题的描述都非常简单,但是通常情况下数据范围会非常大,而朴素方法的时间复杂度过高,导致不能在规定时间内得到问题的解.这时,我们需要一种高效的数据结构来处理这样的问题,在本文中,我们介绍一种基于分治思想的数据结构--线段树. 二 简介 线段树是一种二叉树形结构,属于平衡树的一种.它将线段区间组织成树形的结构,并用每个节点来表示一条线段.一棵[1,10)的线段树的结构如图1.1

经典算法(9) 从归并排序到数列的逆序数对(微软笔试题)

首先来看看原题 微软2010年笔试题 在一个排列中,如果一对数的前后位置与大小顺序相反 ,即前面的数大于后面的数,那么它们就称为一个逆序数对.一个排列中逆序的总数就称为这个排列的逆序 数.如{2,4,3,1}中,2和1,4和3,4和1,3和1是逆序数对,因此整个数组的逆序数对个数为4,现在给定 一数组,要求统计出该数组的逆序数对个数. 计算数列的逆序数对个数最简单的方便就最从前向后依 次统计每个数字与它后面的数字是否能组成逆序数对.代码如下: #include <stdio.h> int ma