手套(线段树+贪心)

你现在有N对手套,但是你不小心把它们弄乱了,需要把它们整理一下。N对手套被一字排开,每只手套都有一个颜色,被记为0~N-1,你打算通过交换把每对手套都排在一起。由于手套比较多,你每次只能交换相邻两个手套。请你计算最少要交换几次才能把手套排整齐(只需要手套配对,不需要手套按从小到大的编号排序)。

30%的数据N≤9;
60%的数据N≤1000;
100%的数据N≤200,000。

输入格式

输入第一行一个N,表示手套对数。
第二行有2N个整数,描述了手套的颜色。每个数都在0~N-1之间,且每个数字都会出现恰好两次。

输出格式

一行,包含一个数,表示最少交换次数。

输入样例

2
1 0 1 0

输出样例

1

将中间两个手套交换过来,颜色序列变成1 1 0 0。

题解:我们考虑第1只手套,和他配对的是第a只,我们把右边的移到最左边总是最优的,如果不是右边移到最左边,就可能会出现另一对手套配对时要跨过当前的手套,而我们把右边的移到最左边就可以避免这种情况。所以我们每次把右边的手套移到左边,但是我们又不能用数组去模拟,那么怎么知道右边的手套移动了多少次呢?

假如枚举到左边的手套在a,且未完成配对,右边的手套在b,则需要移动的次数为(b-a-1)再减去中间已经移到左边的手套数,对于中间移走的手套数,我们考虑用线段树维护,以下标为关键字,1表示移走,求个区间和就可以了。

#include<algorithm>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<fstream>
#include<iostream>
#include<cstring>
using namespace std;

int n,a[400050],id[400020],tree[4500000],vis[400020];
long long ans;

void Updata(int root,int l,int r,int wei,int x)
{
    if (l==r&&r==wei)
    {
        tree[root]+=x;
        return;
    }
    int mid=(l+r)/2;
    if (wei<=mid) Updata(root*2,l,mid,wei,x);
    else Updata(root*2+1,mid+1,r,wei,x);
    tree[root] = tree[root*2]+tree[root*2+1];
}

int Query(int root,int l,int r,int L,int R)
{
    if (L<=l&&r<=R) return tree[root];
    if (R<l||L>r) return 0;
    int mid=(l+r)/2;
    return Query(root*2,l,mid,L,R)+Query(root*2+1,mid+1,r,L,R);
}

int main()
{
    freopen("2067.in","r",stdin);
    freopen("2067.out","w",stdout);
    scanf("%d",&n);
    for (int i=1; i<=2*n; i++)
    {
        scanf("%d",&a[i]);
        id[a[i]] = i;
    }
    for (int i=1; i<=2*n; i++)
    Updata(1,1,2*n,i,1);
    for (int i=1; i<=2*n; i++)
    if (vis[a[i]]==0)
    {
        ans = ans+Query(1,1,2*n,i+1,id[a[i]]-1);
        vis[a[i]]=1;
        Updata(1,1,2*n,id[a[i]],-1);
    }
    printf("%lld\n",ans);
    return 0;
} 
时间: 2024-10-24 01:45:28

手套(线段树+贪心)的相关文章

[Codeforces 1295E]Permutation Separation(线段树+贪心)

[Codeforces 1295E]Permutation Separation(线段树+贪心) 题面 给出一个排列\(p_1,p_2,...p_n\).初始时你需要选择一个位置把排列分成左右两个.然后在两个序列间移动元素使得左边序列的所有元素都比右边的所有元素小.给出每个元素\(p_i\)从一个序列移动到另一个序列的代价\(a_i\). 分析 显然最后得到的序列是小的数在一边,大的数在另一边.设从值为\(i\)的元素处分开之后移动代价为\(ans_i\). 一开始假设所有数都移到右边序列,那么

【Luogu】P1607庙会班车Fair Shuttle(线段树+贪心)

我不会做贪心题啊--贪心题啊--题啊--啊-- 我真TM菜爆了啊-- 这题就像凌乱的yyy一样,把终点排序,终点相同的按起点排序.然后维护一个查询最大值的线段树.对于一个区间[l,r],如果这个区间已经有的最大值为s,那么这个区间最多还能装下c-s头奶牛. 当然奶牛数量没那么多的话我也是没有办法 最后说一句,奶牛到终点就下车了,可以给别的奶牛腾空间,不计入个数.所以奶牛在车上的区间为[l,r-1]. #include <cstdio> #include <iostream> #in

APIO 2012 守卫 | 差分 / 线段树 + 贪心

题目:luogu 3634 首先把为 0 的区间删去,重新标号,可以差分也可以线段树. 把包含其他线段的线段删去,原因 1 是它没有用,原因 2 下面再说.然后,贪心选取最少的点来满足所有线段,即选取还没有点在上面的线段的右端点.如下图中选取的红色方格. 倘若不删去包含其他线段的线段,如上图中的蓝色虚线,我们在贪心选取点的时候,就会先扫到蓝线的左端点而后扫到第二条红线,按照规则,我们会选择蓝线的右端点 6 号点,接下来扫到第二条红线时,由于它上面并没有点被选取,所以又会选取它的右端点 5 号点,

HDU 2795 Billboard (线段树+贪心)

手动博客搬家:本文发表于20170822 21:30:17, 原地址https://blog.csdn.net/suncongbo/article/details/77488127 URL: http://acm.hdu.edu.cn/showproblem.php?pid=2795题目大意:有一个h*w的木板 (h, w<=1e9), 现在有n (n<=2e5)张1*xi的海报要贴在木板上,按1~n的顺序每次贴海报时会选择最上的一排的最左边贴 (海报不能互相覆盖), 求每张海报会被贴在哪一行

HDU 5638 Toposort 线段树+贪心

题意:bc round 74 分析: 参考下普通的用堆维护求字典序最小拓扑序, 用某种数据结构维护入度小于等于k的所有点, 每次找出编号最小的, 并相应的减少k即可. 这个数据结构可以用线段树, 建立一个线段树每个节点[l,r]维护编号从ll到rr的所有节点的最小入度, 查询的时候只需要在线段树上二分, 找到最小的x满足入度小于等于k. 复杂度O((n+m)logn) #include <iostream> #include <cstdio> #include <vector

【HDU】5195-DZY Loves Topological Sorting(拓扑 + 线段树 + 贪心)

每次找出入度小于K的编号最大点. 找的时候用线段树找,找完之后将这个点出度链接的点的入度全部减一 简直爆炸... #include<cstdio> #include<vector> #include<cstring> #include<algorithm> using namespace std; #define lson (pos<<1) #define rson (pos<<1|1) const int maxn = 100005

【BZOJ-3252】攻略 DFS序 + 线段树 + 贪心

3252: 攻略 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 339  Solved: 130[Submit][Status][Discuss] Description 题目简述:树版[k取方格数] 众所周知,桂木桂马是攻略之神,开启攻略之神模式后,他可以同时攻略k部游戏. 今天他得到了一款新游戏<XX半岛>,这款游戏有n个场景(scene),某些场景可以通过不同的选择支到达其他场景.所有场景和选择支构成树状结构:开始游戏时在根节点(共通线)

HDU 5338(ZZX and Permutations-用线段树贪心)

ZZX and Permutations Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) Total Submission(s): 888    Accepted Submission(s): 278 Problem Description ZZX likes permutations. ZZX knows that a permutation can be decompo

BZOJ_1826_[JSOI2010]缓存交换 _线段树+贪心

Description 在计算机中,CPU只能和高速缓存Cache直接交换数据.当所需的内存单元不在Cache中时,则需要从主存里把数据调入Cache.此时,如果Cache容量已满,则必须先从中删除一个. 例如,当前Cache容量为3,且已经有编号为10和20的主存单元. 此时,CPU访问编号为10的主存单元,Cache命中. 接着,CPU访问编号为21的主存单元,那么只需将该主存单元移入Cache中,造成一次缺失(Cache Miss). 接着,CPU访问编号为31的主存单元,则必须从Cach