2023河南萌新联赛第(五)场:郑州轻工业大学-H 三维偏序

2023河南萌新联赛第(五)场:郑州轻工业大学-H 三维偏序

https://ac.nowcoder.com/acm/contest/62977/H

文章目录

  • 2023河南萌新联赛第(五)场:郑州轻工业大学-H 三维偏序
    • 题意
    • 解题思路
    • 代码

题意

链接:https://ac.nowcoder.com/acm/contest/62977/H
来源:牛客网

给定一个由 n n n 个正整数组成的序列 a a a ,你可以通过 j − i j−i ji 个花费交换 a i , a j ( j > i ) a_i,a_j(j>i) ai,aj(j>i) 两个元素。

我们定义一个位置 i i i 是好的,当且仅当 a i a_i ai 不与其他元素发生交换的前提下,使得 a 1 , . . . , a i − 1 ≤ a i a_1,...,a_{i-1}\le a_i a1,...,ai1ai ,即位置 1 ∼ i − 1 1\sim i-1 1i1 上的元素均小于等于 a i a_i ai 。请注意,满足上述要求并不需要 1 ∼ i − 1 1\sim i-1 1i1 中元素有序,只需要满足与 a i a_i ai 的相对大小关系即可。

对于所有的 i ∈ { 1 , 2 , . . . , n } i\in \{1,2,...,n\} i{1,2,...,n} 分别求出使位置 i i i 是好的所需要的最小花费是多少。如果怎么操作都无法使 i i i 位置是好的,则输出 − 1 -1 1

对于每个 i i i ,进行的操作是相互独立的,并没有真正修改原数组的位置。

解题思路

对于 ∑ j − i \sum j-i ji,可以拆分成 ∑ j − ∑ i \sum j-\sum i ji,对于每个确定的 k k k,在 a 1 , . . . , a k − 1 a_1,...,a_{k-1} a1,...,ak1中小于等于 a k a_k ak的我们显然不需要去管它,只需挑出大于 a k a_k ak m m m个交换,所以 ∑ i \sum i i是确定的,只要在 a l + 1 , . . . , a n a_{l+1},...,a_n al+1,...,an中挑出 m m m个下标最小的小于等于 a k a_k ak的即可。

求取 a 1 , . . . , a k − 1 a_1,...,a_{k-1} a1,...,ak1中大于 a k a_k ak的数的个数和下标和,可以用线段树。将 a a a从大到小排序,按序计算,对于已经处理过的打上标记,表明其大于之后的数,对于每一个 i i i求取 1 ∼ i − 1 1\sim i-1 1i1中大于其的数的个数与下标和,记为 m , s u m 1 m,sum1 m,sum1,再在 i + 1 ∼ n i+1\sim n i+1n中求取 m m m个下表最小的小于等于 a i a_i ai的数,可以在线段树上二分查找,记下下标和 s u m 2 sum2 sum2,答案为 s u m 2 − s u m 1 sum2-sum1 sum2sum1

代码

#include
#define ll long long
using namespace std;
const int N=1e5+5;
struct node{
    int sum;ll x;
    node operator +(const node a){
        return node{sum+a.sum,x+a.x};
    }
};
struct tree{
	node tr[N<<3];
    void pushup(int res){tr[res]=tr[res<<1]+tr[res<<1|1];}
    void add(int res,int l,int r,int x,int op){
        if(l==r){
            tr[res].x=x*op,tr[res].sum=op;
            return;
        }
        int mid=l+r>>1;
        if(mid>=x)add(res<<1,l,mid,x,op);
        else add(res<<1|1,mid+1,r,x,op);
        pushup(res);
    }
    node query(int res,int l,int r,int x,int y){
    	if(y=r){
            return tr[res];
        }
        int mid=l+r>>1;
        if(mid>=y)return query(res<<1,l,mid,x,y);
        if(mid>1;
        if(y<=mid)
            return q3(res<<1,l,mid,x,y,w);
        else if(x>=mid+1)
            return q3(res<<1|1,mid+1,r,x,y,w);
        else
        {
            node lq=q3(res<<1,l,mid,x,mid,w);
            if(lq.sum==w)
                return lq;
            node rq=q3(res<<1|1,mid+1,r,mid+1,y,w-lq.sum);
            return lq+rq;
        }
    }
    void build(int res,int l,int r){
        if(l==r){
            tr[res].sum=1,tr[res].x=l;
            return;
        }
        int mid=l+r>>1;
        build(res<<1,l,mid);
        build(res<<1|1,mid+1,r);
        pushup(res);
    }

}a1,a2;
struct Node{
	int x,id;
}b[N<<2];
bool cmp(Node a,Node b){
	return a.x>b.x;
}
ll n,a[N<<2],c[N<<2];
ll work(int x){
//	cout<>n;
	for(int i=1;i<=n;i++)cin>>a[i],b[i].x=a[i],b[i].id=i;
	a2.build(1,1,n);
	sort(b+1,b+n+1,cmp);
	for(int i=1;i<=n;i++){
		if(b[i].x!=b[i-1].x){
			int j=1;
			while(i-j>0&&b[i-j].x==b[i-1].x)a1.add(1,1,n,b[i-j].id,1),a2.add(1,1,n,b[i-j].id,0),j++;
		}
		c[b[i].id]=work(b[i].id);
	}
	for(int i=1;i<=n;i++)cout<

你可能感兴趣的:(2023河南萌新联赛,算法,c++,线段树)