zoukankan      html  css  js  c++  java
  • [题解][笔记]lgP1908逆序对&权值线段树

    原题链

    这个题其实完全不必用权值线段树去做,只是现在有点看不懂树状数组线段树用途更多,而且我要学线段树合并的原因

    算法概述:

    权值线段树其实和普通线段树没有什么本质上的区别,只是维护的东西不一样,平时我们做的线段树是维护的区间和,而权值线段树维护的是某个数或几个数出现次数的和.同时应该注意的是权值线段树的定义中的(l,r)跟平常普通的线段树表示的是区间的左右端点不同,它表示的是值域,也就是数值.

    关于本题

    这个题要求的是逆序对,先观察数据范围,发现数据范围很大,需要离散化,离散化其实也不难,就是重新映射到一个新的小的连续的整数序列上(看代码就知道了).还有很多细节都在代码里有注释,光靠口讲有点抽象,大家就凑合着看代码吧

    代码

    #include <bits/stdc++.h>
    using namespace std;
    long long n,a[1000010];
    struct tmp{
    	long long val,id;
    }b[1000010];
    struct node{
    	long long l,r,sum;//权值线段树的下标l,r是值域而不是普通数组的下标
    }tree[1000010 * 4];
    bool cmp(tmp x,tmp y){
    	return x.val < y.val;
    }
    void build(long long num,long long l,long long r){
    	tree[num].l = l;tree[num].r = r;
    	if(l == r)return;
    	long long mid = (l + r) / 2;
    	build(num * 2,l,mid);build(num * 2 + 1,mid + 1,r);
    }
    long long ask(long long num,long long tar){
    	if(tree[num].l == tree[num].r)return tree[num].sum;
    	long long mid = (tree[num].l + tree[num].r) / 2;
    	if(tar <= mid)
    		return ask(num * 2,tar) + tree[num * 2 + 1].sum;
    	else return ask(num * 2 + 1,tar);
    	
    }
    void change(long long num,long long tar){
    	if(tree[num].l == tree[num].r){
    		tree[num].sum++;
    		return;
    	}
    	long long mid = (tree[num].l + tree[num].r) / 2;
    	if(tar <= mid)
    		change(num * 2,tar);
    	else change(num * 2 + 1,tar);
    	tree[num].sum = tree[num * 2].sum + tree[num * 2 + 1].sum;
    }
    int main(){
    	scanf("%lld",&n);
    	for(long long i = 1;i <= n;i++){
    		scanf("%lld",&a[i]);
    		b[i].val = a[i]; //离散化
    		b[i].id = i;
    	}
    	sort(b + 1,b + n + 1,cmp);
    	long long cnt = 0;
    	for(long long i = 1;i <= n;i++){
    		if(b[i].val != b[i - 1].val || i == 1)cnt++;
    		a[b[i].id] = cnt;
    	}//离散化结束,现在的数列是一个从1开始的连续的数列
    	build(1,1,n);
    	long long ans = 0;
    	for(long long i = 1;i <= n;i++){
    		ans += ask(1,a[i] + 1);//权值线段树计算的是大于等于x的数的个数
    		//而题目中要求严格大于,所以要加1.
    		//因为离散化了所以保证了数据是连续的,+1后一定会是下一个数
    		change(1,a[i]);//出现了一次,就加一个sum
    	}
    	printf("%lld
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    selective search生成.mat文件
    2014 百度之星 1003 题解 Xor Sum
    hdu 2544 最短路
    表解锁
    第 10 章 数据结构
    MySQL Study之--Percona Server版本号
    const 不再迷茫
    opecv2 MeanShift 使用均值漂移算法查找物体
    server用JDBC对mysql数据库进行操作
    Django Admin site 显示问题
  • 原文地址:https://www.cnblogs.com/czy--blog/p/13864238.html
Copyright © 2011-2022 走看看