Codeforces Round #834 (Div. 3) G 正难则反-并查集/线段树-二分

考虑的方向有多种,一种是先考虑最小的位置他的旁边填什么,但是不能随便填有很多的限制,不好做。

一种是考虑第一个位置填什么,考虑试填最小的再看填这个其他的位置是否有数可填。

后面这个东西其实就是在当前要填的数x 当前限制y 即x~y这个区间内的数字是否有数可填。查一下区间最小值即可。

但是当前要填的数x要一个个枚举 明显x具有单调性 所以可以进行二分。这样就得到了一个线段树+二分的做法。

接下来考虑简单的方法,再考虑从最大的数字填发现还是不好满足字典序最小的性质。

最后考虑从末尾填 这下我知道了要填一个尽可能大的数字才让前面填的数字字典序小,这样既满足了字典序最优又满足了合法性最优。

找这个数字可以利用前缀和+倍增来找,也可以使用链表复杂度降到O(n) 我不太想写太复杂用了并查集。

这道题的多个方向非常的巧妙。体现了正难则反的思想。

code
//#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<ctime>
#include<cctype>
#include<queue>
#include<deque>
#include<stack>
#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<cctype>
#include<cstdlib>
#include<queue>
#include<deque>
#include<stack>
#include<vector>
#include<algorithm>
#include<utility>
#include<bitset>
#include<set>
#include<map>
#define ll long long
#define db double
#define INF 2000000000
#define inf 100000000000000000ll
#define ldb long double
#define pb push_back
#define put_(x) printf("%d ",x);
#define get(x) x=read()
#define putl(x) printf("%lld\n",x)
#define rep(p,n,i) for(int i=p;i<=n;++i)
#define go(x) for(int i=lin[x],tn=ver[i];i;tn=ver[i=nex[i]])
#define pii pair<int,int>
#define mk make_pair
#define P 1000000007ll
#define gf(x) scanf("%lf",&x)
#define pf(x) ((x)*(x))
#define uint unsigned long long
#define ui unsigned
#define sq sqrt
#define l(x) s[x].l
#define r(x) s[x].r
#define S second
#define mod 1000000007
#define sc(A) scanf("%d",&A)
#define scs(A) scanf("%s",A);
#define put(A) printf("%d\n",A)
#define min(x,y) (x>=y?y:x)
#define max(x,y) (x>=y?x:y)
using namespace std;
const int MAXN=200010;
int len,n,m,T,sum;
int a[MAXN],vis[MAXN],f[MAXN];
inline int getfather(int x)
{
	return x==f[x]?x:f[x]=getfather(f[x]);
}
int main()
{
	freopen("1.in","r",stdin);
	sc(T);
	while(T--)
	{
		int flag=0;
		sc(n);m=n/2;
		rep(1,n,i)f[i]=i,vis[i]=0;
		rep(1,m,i)
		{
			sc(a[i<<1]);
			if(vis[a[i<<1]])flag=1;
			vis[a[i<<1]]=1;
		}
		for(int i=m;i>=1;--i)
		{
			int cc=a[i<<1];
			int ww=getfather(cc);
			while(vis[ww])
			{
				if(ww==1){flag=1;break;}
				int kk=getfather(ww-1);
				f[ww]=kk;
				ww=kk;
			}
			if(flag)break;
			a[(i<<1)-1]=ww;
			vis[ww]=1;
		}
		if(flag)puts("-1");
		else
		{
			rep(1,n,i)put_(a[i]);
			puts("");
		}
	}
	return 0;
}
posted @ 2022-11-21 11:05  chdy  阅读(22)  评论(0编辑  收藏  举报