[JLOI2013] 항목 삭제

두 개의 말뚝을 모으고 분할 지점을 중간으로 설정합니다. 삭제는 숫자의 내림차순으로 만 수행 할 수 있기 때문에 실제로 쓸모없는 작업을 반복하지 않는 한 작업 횟수는 확실합니다.
먼저 숫자를 정렬하고 숫자의 위치를 ​​기록합니다. 가장 큰 것에서 가장 작은 것까지 삭제합니다. 각 숫자의 위치와 구분 점 사이의 거리에 따라 각 숫자를 삭제할 이동 횟수를 계산합니다. 숫자를 삭제 한 후 그에 따라 구분 점의 위치를 ​​이동합니다.
현재 가장 큰 숫자를 삭제하고 싶지만 한 힙의 숫자가 힙의 맨 위에 있지 않은 경우 동일한 힙의 작은 숫자를 모두 다른 힙으로 이동해야하며 이동 한 후에는 두 힙을 이동해야합니다. 숫자는 변경되며 mid는 두 파일 사이의 분할 지점 위치를 나타냅니다.
특정 번호가 삭제되면 단일 수정 지점이 수행됩니다. 데이터 구조를 사용하여 간격 합계 값을 유지하고 간격 합계 값을 쿼리합니다.
#include <bits/stdc++.h>
#define int long long
#define lowbit(x) x&(-x)
using namespace std;
const int N=1e5+5;
int n1,n2,n,now,ans;
int c[N];
struct number{
    
    int x,pos;}num[N];

inline void change(int x,int v)
{
    
    
	while (x<=n)
	{
    
    
		c[x]+=v;
		x+=lowbit(x);
	}
}
inline int query(int x)
{
    
    
	int res=0;
	while (x)
	{
    
    
		res+=c[x];
		x-=lowbit(x);
	}
	return res;
}

inline bool cmp(number a,number b){
    
    return a.x>b.x;}

signed main(){
    
    
	scanf("%lld%lld",&n1,&n2);
	n=n1+n2+1;
	now=n1+1;
	for (register int i=n1; i>=1; --i) scanf("%lld",&num[i].x),num[i].pos=i,change(i,1);
	for (register int i=n1+2; i<=n; ++i) scanf("%lld",&num[i].x),num[i].pos=i,change(i,1);
	num[now].pos=now;
	sort(num+1,num+n+1,cmp);
	for (register int i=1; i<n; ++i)
	{
    
    
		change(num[i].pos,-1);
		if (now<num[i].pos) ans+=query(num[i].pos)-query(now);	
		else ans+=query(now)-query(num[i].pos);
		now=num[i].pos;
	}
	printf("%lld\n",ans);
return 0;	
}

추천

출처blog.csdn.net/Dove_xyh/article/details/107840518