离散化入门模板(线段树离散)HDU - 3333、CodeForces - 540E

模板:

vector<int> v;
int getid(int k)
{
    return lower_bound(v.begin(),v.end(),k)-v.begin()+1;
}
for(int i=1;i<=N;i++){scanf("%d",&s[i]);
            v.push_back(s[i]);}
sort(v.begin(),v.end());
v.erase(unique(v.begin(),v.end()),v.end());
getid(s[p]);

Turing Tree HDU - 3333

http://acm.hdu.edu.cn/showproblem.php?pid=3333
题解链接:https://blog.csdn.net/T__TSZ/article/details/77529140
题解我懒得打。这个题解可以的。由于这里重点在离散化所以下面的代码直接是从代码基础改的。用离散模板改的。实测比原答案快。
#include<iostream>
#include<algorithm>
#include <vector>
#include<cstdio>
#include<cstring>
using namespace std;
#define ls o<<1
#define rs o<<1|1
#define lson L,mid,ls
#define rson mid+1,R,rs
#define mdzz int mid=(L+R)>>1;
int N,M;
long long tree[120005];
int s[30005];
int hashs[30005];
int vis[30005];
long long ans[100003];
struct node
{
    int l,r,t;
    bool operator <(const node &a)const
    {
        return a.r>r;
    }
}q[200003];
void pushup(int o){
    tree[o]=tree[ls]+tree[rs];
}
void update(int p,int L,int R,int o,int v){ //点修改
    if(L==R){
        tree[o]+=v;
        return;
    }
    mdzz;
    if(p<=mid) update(p,lson,v);
    else update(p,rson,v);
    pushup(o);
}
long long query(int l,int r,int L,int R,int o){//[l,r]区间询问
    if(r>=R&&l<=L) return tree[o];
    mdzz;
    long long ans=0;
    if(l<=mid)
        ans+=query(l,r,lson);
    if(r>mid)
        ans+=query(l,r,rson);
    return ans;
}
vector<int> v;
int getid(int k)
{
    return lower_bound(v.begin(),v.end(),k)-v.begin()+1;
}

int main()
{
    int T;
    scanf("%d",&T);
    int a,b;
    while(T--)
    {
        memset(vis,0,sizeof vis);
        memset(tree,0,sizeof tree);
        memset(hashs,0,sizeof hashs);
        scanf("%d",&N);
        for(int i=1;i<=N;i++){scanf("%d",&s[i]);
            v.push_back(s[i]);}
        scanf("%d",&M);
        for(int i=1;i<=M;i++)
        {
            scanf("%d%d",&q[i].l,&q[i].r);
            q[i].t=i;
        }

        sort(v.begin(),v.end());
        v.erase(unique(v.begin(),v.end()),v.end());

        sort(q+1,q+M+1);
        int p=1;
        for(int i=1;i<=M;i++)
        {
            while(p<=q[i].r)
            {
                int temp=getid(s[p]);
                if(vis[temp])
                    update(vis[temp],1,N,1,-s[p]);
                vis[temp]=p;
                update(p,1,N,1,s[p]);
                p++;
            }
            ans[q[i].t]=query(q[i].l,q[i].r,1,N,1);
        }
        for(int i=1;i<=M;i++)printf("%lld\n",ans[i]);

    }
    return 0;
}

Infinite Inversions CodeForces - 540E

离散化+树状数组
树状数组入门:(简洁清楚)https://blog.csdn.net/Small_Orange_glory/article/details/81290634
嫌麻烦的看这里:sum函数求(1,x)的值得和。update更新x和与x有关的值。lowbit是树状数组特有的一个用来调节点的。(不想看原理的话知道这些就可以写这道题了)
题目来源:https://codeforces.com/problemset/problem/540/E
代码来源:https://blog.csdn.net/whai362/article/details/48827207
题解: 如何通过树状数组实现求逆序对。 把数字投到书里面,找比数大的有多少个就是当前逆序对(模拟一下)但是这里是无限序列,不能一个个投。
构造:要简单构造一下。如果强行构造整个数列(样例构造4132时会比较麻烦的,这里只是空了一个,如果给你两个操作交换12和10000 10001全构造就gg了)不太好,所以把交换的数放到pool里面,然后遇到断层,就添一个新的数进去记录中间有多少(具体看代码中循环1).这样就基本构造完了。
离散:然后离散化(用id)要投的全都准备好。
模拟:然后模拟交换。
寻找:最后从尾部开始往里面头找比自己小的(从头也可以就找比自己大呗就是麻烦了点,这里头尾指的是交换玩顺序)最后输出答案即可。

重点离散化看这里:

以下为未离散的代码(是不能a的,但是跟下面代码做比较可以清晰看出哪里是离散部分。一开始我以为pool是用来离散的,后面发现是题目本来需要的,这里只是用id进行了离散。不同点用注释!!!表示出来,不离散的的话,这个题可以写的更简单只是为了对比**所以第一个代码是在第二个改的)

#include <iostream>
#include <cstdio>
#include <vector>
#include <map>
#include <algorithm>
using namespace std;

#define P pair<int ,int>
#define PB push_back
#define X first
#define Y second
#define LL long long

const int N = 1e5 + 5;

vector<P> pool;
int pool_cnt;

int u[N], v[N];

int id[N * 4];
int num[N * 4];

int BIT[N * 4];
int lowbit(int x) { return x & -x; }
int sum(int x) {
    int s = 0;
    while (x > 0) {
        s += BIT[x];
        x -= lowbit(x);
    }
    return s;
}int maxx=-1;
void update(int x, int c) {
    while (x <= maxx) {//!!!
        BIT[x] += c;
        x += lowbit(x);
    }
}

int get_p(int x) {
    return lower_bound(pool.begin(), pool.begin() + pool_cnt, P(x, 0)) - pool.begin() + 1;
}

int main() {
    int n;
    cin>>n;
    for(int i = 0; i < n; ++i) {
        cin>>u[i]>>v[i];
        pool.PB(P(u[i], 1));
        pool.PB(P(v[i], 1));
        maxx=max(maxx,max(u[i],v[i]));
    }
    sort(pool.begin(), pool.end());
    pool_cnt = unique(pool.begin(), pool.end()) - pool.begin();
    for(int i = 0; i < pool_cnt - 1; ++i) {//循环1
        int x = pool[i].X + 1;
        if(x == pool[i + 1].X) continue;
        int y = pool[i + 1].X - x;
        pool.PB(P(x, y));
    }
    sort(pool.begin(), pool.end());
    pool_cnt = unique(pool.begin(), pool.end()) - pool.begin();
    for(int i = 0; i < pool_cnt; ++i) {
        id[i + 1] = pool[i].X;//!!!
        num[pool[i].X] = pool[i].Y;//!!!
    }
    for(int i = 0; i < n; ++i) {
        u[i] = get_p(u[i]);
        v[i] = get_p(v[i]);
        swap(id[u[i]], id[v[i]]);
    }
    LL ans = 0;
    for(int i = pool_cnt; i > 0; --i) {
        LL tmp = sum(id[i]);
        ans += tmp * num[id[i]];
//        cout<<tmp<<id[i]<<num[id[i]]<<endl;
        update(id[i], num[id[i]]);
    }
    cout<<ans<<endl;
    return 0;
}

以下离散

#include <iostream>
#include <cstdio>
#include <vector>
#include <map>
#include <algorithm>
using namespace std;
 
#define P pair<int ,int>
#define PB push_back
#define X first
#define Y second
#define LL __int64
 
const int N = 1e5 + 5;
 
vector<P> pool;
int pool_cnt;
 
int u[N], v[N];
 
int id[N * 4];
int num[N * 4];
 
int BIT[N * 4];
int lowbit(int x) { return x & -x; }
int sum(int x) {
	int s = 0;
	while (x > 0) {
		s += BIT[x];
		x -= lowbit(x);
	}
	return s;
}
void update(int x, int c) {
	while (x <= pool_cnt) {//!!!
		BIT[x] += c;
		x += lowbit(x);
	}
}
 
int get_p(int x) {
	return lower_bound(pool.begin(), pool.begin() + pool_cnt, P(x, 0)) - pool.begin() + 1;
}
 
int main() {
	int n;
	cin>>n;
	for(int i = 0; i < n; ++i) {
		cin>>u[i]>>v[i];
		pool.PB(P(u[i], 1));
		pool.PB(P(v[i], 1));
	}
	sort(pool.begin(), pool.end());
	pool_cnt = unique(pool.begin(), pool.end()) - pool.begin();
	for(int i = 0; i < pool_cnt - 1; ++i) {
		int x = pool[i].X + 1;
		if(x == pool[i + 1].X) continue;
		int y = pool[i + 1].X - x;
		pool.PB(P(x, y));
	}
	sort(pool.begin(), pool.end());
	pool_cnt = unique(pool.begin(), pool.end()) - pool.begin();
	for(int i = 0; i < pool_cnt; ++i) {
		id[i + 1] = i + 1;//!!!
		num[i + 1] = pool[i].Y;//!!!
	}
	for(int i = 0; i < n; ++i) {
		u[i] = get_p(u[i]);
		v[i] = get_p(v[i]);
		swap(id[u[i]], id[v[i]]);
	}
	LL ans = 0;
	for(int i = pool_cnt; i > 0; --i) {
		LL tmp = sum(id[i]);
		ans += tmp * num[id[i]];
		update(id[i], num[id[i]]);
	}
	cout<<ans<<endl;
	return 0;
}

我的AC代码(不用看了之前差不多。只是自己写了放在这里记录一下。)一开始下面求和开错了还有前面有个地方循环限制写错了,错了几发忧桑。

#include <iostream>
#include <cstdio>
#include <vector>
#include <map>
#include <algorithm>
using namespace std;

#define P pair<int ,int>
#define X first
#define Y second
typedef long long ll;

const int N = 1e5 + 5;


int BIT[N * 4];
int lowbit(int x) { return x & -x; }
int sum(int x) {
    int s = 0;
    while (x > 0) {
        s += BIT[x];
        x -= lowbit(x);
    }
    return s;
}
void update(int x, int c,int mx) {
    while (x <= mx) {//!!!
        BIT[x] += c;
        x += lowbit(x);
    }
}
vector<P> pool;
int length;
int u[N], v[N];
int id[N * 4];
int num[N * 4];

int get_p(int x) {
    return lower_bound(pool.begin(), pool.begin() + length, P(x, 0)) - pool.begin();
}
int main()
{
    int n;scanf("%d",&n);
    for(int i=0;i<n;i++){
        scanf("%d%d",&u[i],&v[i]);
        pool.push_back(P(u[i],1));
        pool.push_back(P(v[i],1));
    }
    sort(pool.begin(),pool.end());
    length = unique(pool.begin(), pool.end()) - pool.begin();
    for(int i=0;i<length-1;i++){
        if(pool[i].X+1==pool[i+1].X)continue;
        int cishu=pool[i+1].X-pool[i].X-1;
        pool.push_back(P(pool[i].X+1,cishu));
    }
    sort(pool.begin(),pool.end());
    length = unique(pool.begin(), pool.end()) - pool.begin();
    for(int i=0;i<length;i++){
        id[i+1]=i+1;
        num[i+1]=pool[i].Y;
//        cout<<i+1<<pool[i].X<<pool[i].Y<<endl;
    }
    for(int i=0;i<n;i++){
        int loca1=get_p(u[i])+1;
        int loca2=get_p(v[i])+1;
        swap(id[loca1],id[loca2]);
    }
    ll ans=0;
    for(int i=length;i>0;i--){
        ll temp=sum(id[i]);
        ans+=temp*num[id[i]];
        update(id[i],num[id[i]],length);
    }
    printf("%lld",ans);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值