• Codeforces Round #638 (Div. 2) F. Phoenix and Memory 区间贪心+线段树


    Codeforces Round #638 (Div. 2) F. Phoenix and Memory 区间贪心+线段树

    题意

    有n个人,标号为1--n,他们站的顺序未知,已知每个位置可能的标号范围为[a,b],要求还原朋友的站位顺序,同时,需要考虑还原后的站位是否是唯一的,如果不唯一,随意输出两种合法顺序

    分析

    还原顺序不难,其实是一个看起来很熟悉的问题。记录每个点开始的右边界,维护当前可选的点以及该右边界,从左往右扫,每次取最小的右边界,即可贪心得出合法的序列。该题的难点关键在于判断是否唯一。
    设编号为i的人的位置为(pos_i),那么问题就是存不存在(L_{pos_j}<=pos_i<pos_j<=R_{pos_i})如果存在那么他们两个就可以互相交换了。我们考虑最暴力的做法,就是对于每个人i来说找到一个j满足以上条件,复杂度(O(n^2))。我们进一步思考,对于第i个人来说,要找到([1,n])里面有一个j满足以上不等式(注意,这里i,j不一定对应不等式里面的i,j它们可以互换例如(pos_i>pos_j)但是按照逻辑这个不等式仍然成立只是换了i,j),而由于(R[pos[i]])已经确定了,也就是找到人的标号在([1,R[pos[i]]])里面满足条件的j,由于是一对一对找,我们可以直接找([i+1,R[pos[i]])标号的人,对于该区间内的标号,pos[i]的人的标号可以变成这个区间里面的人的标号,因为i所在位置的L最小都是i,所以毋庸置疑可以变,而如果这个区间里面的最小(L)是小于等于i的,代表这个区间里面最小的L的位置的标号可以变成i位置的标号,这就代表了两两可以互换。(这里要是细看细节还是挺绕的。。)

    #include<bits/stdc++.h>
    using namespace std;
    #define pb push_back
    #define F first
    #define S second
    #define mkp make_pair
    #define pii pair<int,int>
    typedef long long ll;
    const int inf=0x3f3f3f3f;
    const int maxn=2e5+10;
    int tree[maxn<<2],id[maxn<<2];
    int ans[maxn],pos[maxn],L[maxn],R[maxn];
    int n;
    vector<pair<int,int> >v[maxn]; 
    void build(int o,int l,int r){
    	if(l==r){
    		tree[o]=L[pos[l]];
    		id[o]=l;
    		return ;
    	}
    	int mid=l+r>>1;
    	build(o<<1,l,mid);
    	build(o<<1|1,mid+1,r);
    	if(tree[o<<1]<tree[o<<1|1])id[o]=id[o<<1];
    	else id[o]=id[o<<1|1];
    	tree[o]=min(tree[o<<1|1],tree[o<<1]);
    }
    pair<int,int> query(int o,int l,int r,int x,int y){
    	if(x<=l&&y>=r)return mkp(tree[o],id[o]);
    	int mid=l+r>>1;
    	pair<int,int>tmp1=mkp(-1,-1),tmp2=mkp(-1,-1);
    	if(mid>=x)tmp1=query(o<<1,l,mid,x,y);
    	if(mid<y)tmp2=query(o<<1|1,mid+1,r,x,y);
    	if(tmp1.first==-1)return tmp2;
    	if(tmp2.first==-1)return tmp1;
    	if(tmp1.first>tmp2.first)return tmp2;
    	else return tmp1;
    }
    void print(){
    	for(int i=1;i<=n;i++){
    		cout<<ans[i]<<" ";
    	}
    	cout<<endl;
    }
    int main(){
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++){
    		scanf("%d%d",&L[i],&R[i]);
    		v[L[i]].pb(mkp(R[i],i));
    	}
    	set<pair<int,int> >s;
    	for(int i=1;i<=n;i++){
    		s.insert(v[i].begin(),v[i].end());
    		ans[(*s.begin()).second]=i;
    		pos[i]=(*s.begin()).second;
    		s.erase(s.begin());	
    	}
    	build(1,1,n);
    	for(int i=1;i<=n;i++){
    		pair<int,int>tmp=query(1,1,n,i+1,R[pos[i]]);
    		if(i+1>R[pos[i]])continue;
    		if(tmp.first<=i){
    			//cout<<tmp.first<<" "<<tmp.second<<endl;
    			printf("NO
    ");
    			print();
    			swap(ans[pos[tmp.second]],ans[pos[i]]);
    			print();
    			return 0;
    		}
    	}
    	printf("YES
    ");
    	print();
    	
    }
    
  • 相关阅读:
    js数组操作
    docker操作命令
    swoole使用案例
    swoole实现视频弹幕效果
    swoole的UDP服务
    swoole的TCP服务
    安装回环网卡&安装Linux前准备
    Linux之安装Linux详细步骤
    Spring Boot的面试题
    Shell 脚本面试问题大全
  • 原文地址:https://www.cnblogs.com/ttttttttrx/p/12818372.html
Copyright © 2020-2023  润新知