线段树 单点更新

hdu 1394

题意:给出一个0到n-1的排列, 求题目所给的所有形式的最小逆序数

1 暴力

#include <cstdio>
#include <algorithm>
using namespace std;
int a[5010], n;
int main()
{
	while(scanf("%d", &n) == 1)
	  {
	  	 int ans1, ans = 0;
	  	 for(int i=1; i<=n; i++)
	  	 	scanf("%d", &a[i]);
	  	 for(int i=1; i<=n-1; i++)
	  	 	for(int j=i+1; j<=n; j++)
	  	 	  if(a[i] > a[j])
	  	 	  	 ans++;
	  	 ans1 = ans;
	  	 for(int i=1; i<=n-1; i++)
	  	   {
              int count = 0;
              for(int j=2; j<=n; j++)
              	 if(a[1] > a[j])
              	   count++;
              ans1 = ans1-count+n-1-count;
              ans = min(ans, ans1);
              int t = a[1];
              for(int j=2; j<=n; j++)
              	a[j-1] = a[j];
              a[n] = t;
          }
         printf("%d\n", ans);
	  }
	return 0;
}


2 线段树

node[0]表示节点对应区间的已插入数字个数, 当输入X时, 需求x到n的已插入个数

#include <cstdio>
#include <algorithm>
using namespace std;
int node[5010*4], a[5010], n, x;
void construct(int o, int l, int r)
{
  node[o] = 0;
  if(l != r)
  	 {
  	 	int m = (l+r) / 2;
  	 	construct(2*o, l, m);
  	 	construct(2*o+1, m+1, r); 
  	 }
}
void update(int o, int l ,int r)
{
  if(l == r)
  	node[o] = 1;
  else 
   {
   	  int m = (l+r) / 2;
   	  if(x <= m)
   	  	update(2*o, l, m);
   	  else 
   	  	update(2*o+1, m+1, r);
   	  node[o] = node[2*o] + node[2*o+1];
   }
}
int query(int o, int l, int r)
{
  if(l>=x+1)
   return node[o];
  if(r < x+1)
   return 0;
  int m = (l+r) / 2;
  return query(2*o, l, m) + query(2*o+1, m+1, r);
}
int main()
{
	while(scanf("%d", &n) == 1)
	 {
	 	construct(1, 1, n);
	 	int ans, count1, count2;
	 	ans = 0;
	 	for(int i=1; i<=n; i++)
	 	  {
	 	  	scanf("%d", &x);
	 	  	x++;
	 	  	a[i] = x;
	 	  	update(1, 1, n);
	 	  	ans += query(1, 1, n);
	 	  }
	 	count1 = ans;
	 	for(int i=1; i<n; i++)
	 	  {
	 	  	count2 = 0;
	 	  	for(int j=2; j<=n; j++)
	 	  	  if(a[1] > a[j])
	 	  	  	 count2++;
	 	  	count1 = count1-count2+n-1-count2;
	 	  	ans = min(ans, count1);
	 	  	int t = a[1];
	 	  	for(int j=2; j<=n; j++)
	 	  	  a[j-1] = a[j];
	 	  	a[n] = t;
	 	  }
        printf("%d\n", ans);
	 }
	return 0;
}



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值