• [bzoj3192][JLOI2013]删除物品_树状数组_栈


    删除物品 bzoj-3192 JLOI-2013

    题目大意:给你n个物品,分成2堆。所有的物品有不同的优先级。我只可以将一堆中的堆顶移动到另一个堆的堆顶。而如果当前物品是全局所有物品中优先级最高的,我可以直接将其删除。询问最小移动多少次,删除不计入总次数。

    注释:$1le nle 10^5$。

    想法:显然是两个栈。开始以为是每个堆中优先级最高的,然后一顿瞎想。如果是全局优先级最高的,就相当于弄两个栈,然后将两个栈顶对顶对到一起,开始指针在两个栈顶之间。那么栈顶的移动就相当于物品的移动。显然答案在序列给出后就是固定的,就是从当前点到整个序列最大值的的有多少个方块隔着,将答案加上即可。而这个找最大值的过程可以用树状数组实现。

    最后,附上丑陋的代码... ...

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    #include <cstdlib>
    typedef long long ll;
    using namespace std;
    int n,m,tree[100005];
    struct Node
    {
    	int x,id;
    }a[100005];
    void del(int x)
    {
    	for(int i=x;i<=n;i+=(i&(-i)))
    		tree[i]--;
    }
    int getsum(int x)
    {
    	int t=0;
    	for(int i=x;i;i-=(i&(-i))) t+=tree[i]; return t;
    }
    bool cmp(Node u,Node v)
    {
    	return u.x>v.x;
    }
    int main()
    {
    	scanf("%d%d",&n,&m);
    	a[0].id=n;
    	for(int i=n;i;i--)
    	{
    		scanf("%d",&a[i].x);
    		a[i].id=i;
    	}
    	for(int i=1;i<=m;i++)
    	{
    		scanf("%d",&a[++n].x);
    		a[n].id=n;
    	}
    	sort(a+1,a+n+1,cmp);
    	for(int i=1;i<=n;i++)
    		tree[i]=(i&(-i));
    	ll ans=0;
    	for(int i=1;i<=n;i++)
    	{
    		if(a[i].id>a[i-1].id)
    			ans+=getsum(a[i].id-1)-getsum(a[i-1].id);
    		else
    			ans+=getsum(a[i-1].id)-getsum(a[i].id);
    		del(a[i].id);
    	}
    	printf("%lld
    ",ans);
    	return 0;
    }

    小结:这种问题的转化是本质,剩下的实现反而显得平凡。

  • 相关阅读:
    洛谷 [P1024]一元三次方程求解
    洛谷 [P1426] 通往奥格瑞玛的道路
    洛谷 [p1439] 最长公共子序列 (NlogN)
    洛谷 [P1182] 数列分段
    洛谷 [P1314] 聪明的质检员(NOIP2011 D2T2)
    洛谷 [P1280] 尼克的任务
    洛谷 [P1801] 黑匣子
    洛谷 [p1196] 银河英雄传说
    洛谷 [P2024] 食物链
    洛谷 [P1198] 最大数
  • 原文地址:https://www.cnblogs.com/ShuraK/p/9088644.html
Copyright © 2020-2023  润新知