Loading

2018牛客暑期多校J - Hash Function (线段树优化建边 + 拓扑排序)

image
思路:
考虑一个数\(a_i\)现在所处的位置\(cur\)和原本应该处于的位置\(pos\)之间的关系,既然\([cur,pos]\)的位置\(a_i\)都不能插入,那么就意味着,\([cur,pos]\)这些位置的数在哈希的插入序列中必须在当前这个数\(a_i\)的前面。
一些数在序列中的位置相对于其他一些数有要求,那么我们就可以想到拓扑排序,但是这是区间内的所有数对一个点同时连边,直接做时间复杂度肯定是不可以的,但是这个东西可以被线段树优化建图来解决,那么到此问题就解决了,优化建图后,直接拓扑即可。
对于题目中提到的\(-1\)的情况,有可能是无法形成拓扑序,再有一种可能就是题目原本的插入序列就是不合法的,即一个数当前的位置和它原本应该在的位置之间有若干个\(-1\)存在,这种情况也是-1。

#include <bits/stdc++.h>

using namespace std;

#define pb push_back
#define eb emplace_back
#define MP make_pair
#define pii pair<int,int>
#define pll pair<ll,ll>
#define lson rt<<1
#define rson rt<<1|1
#define CLOSE std::ios::sync_with_stdio(false)
#define sz(x) (int)(x).size()
typedef long long ll;
typedef double db;
const int INF = 0x3f3f3f3f;
const db eps = 1e-6;
const int N = 2e6 + 10;

int n,a[N],tro[N],id[N],indegree[N];
std::vector<int>G[N];
void add(int u,int v) {
	G[u].pb(v);
}
void build(int rt,int l,int r) {
	id[rt] = indegree[rt] = 0;
	if(l == r) {
		id[rt] = l;
		tro[l] = rt; 
		return ;
	}
	int mid = (l + r) >> 1;
	build(lson,l,mid); build(rson,mid+1,r);
	add(lson,rt); add(rson,rt);
	indegree[rt]+=2;
}
void modify(int rt,int l,int r,int L,int R,int u) {
	if(l >= L && r <= R) {
		add(rt,u);
		indegree[u]++;
		return ;
	}
	int mid = (l + r) >> 1;
	if(L <= mid) modify(lson,l,mid,L,R,u);
	if(R > mid) modify(rson,mid+1,r,L,R,u);
}

int sum[N];
std::vector<int>ans;
void tuposort() {
	ans.clear();
	priority_queue<pii,vector<pii>,greater<pii> >q;
	for(int i = 1;i <= n;i ++) {
		if(a[i] == -1) continue;
		if(indegree[tro[i]] == 0) {
			q.push({a[i],tro[i]});
		}
	}
	while(!q.empty()) {
		int u = q.top().second; 
		q.pop();
		if(id[u]) {
			ans.pb(a[id[u]]);
		}
		for(auto v : G[u]) {
			--indegree[v];
			if(indegree[v] == 0) {
				if(!id[v]) q.push({-1,v});
				else q.push({a[id[v]],v});
			}
		}
	}
}

void init() {
	for(int i = 0;i <= n * 10;i ++) G[i].clear();
}

void solve() {
	scanf("%d",&n);
	for(int i = 1;i <= n;i ++) {
		scanf("%d",&a[i]);
	}
	init();
	for(int i = 1;i <= n;i ++) {
		a[i] == -1 ? sum[i] = sum[i-1] + 1 : sum[i] = sum[i-1];
	}
	if(sum[n] == n) {
		printf("\n"); return ;
	}
	// inittree(1,1,n);
	build(1,1,n);
	for(int i = 1;i <= n;i ++) {
		if(a[i] == -1) continue;
		int sd = a[i] % n + 1;
		if(sd == i) continue;
		if(sd < i) {
			if(sum[i] - sum[sd-1] > 0) {
				printf("-1\n"); return ;
			} 
			modify(1,1,n,sd,i-1,tro[i]);
		}
		if(sd > i) {
			if(sum[i] + sum[n] - sum[sd-1] > 0) {
				printf("-1\n"); return ;
			}
			modify(1,1,n,sd,n,tro[i]);
			if(i > 1) modify(1,1,n,1,i-1,tro[i]);
		}
	}	

	tuposort();			
	if(sz(ans) == n - sum[n]) {
		for(int i = 0;i < sz(ans);i ++) printf(i == sz(ans) - 1 ? "%d\n" : "%d ",ans[i]);
	}																					
	else {
		printf("-1\n");
	}	
}	

int main() {
	int T;scanf("%d",&T);
	while(T--) solve();
	return 0;
}
posted @ 2021-10-06 09:29  x7x7g7c7  阅读(71)  评论(0)    收藏  举报