记录一下学到的新姿势:线段树优化建图
题目大意:
已知哈希函数为 hash(x) = x mod n ,且如果出现哈希冲突,则 hash(x) = hash(x+1)。
现给出一张 hash 表,长度为 n,问字典序最小插入顺序。
知识点: 线段树优化建图、拓扑排序
解题思路:
对于一个数 x,设它所在的位置为 pos,如果 pos ≠ x%n,则 pos 左边,x%n 及其右边所有的数都要在 x 之前插入(如果这个区间里面有 -1,那么输出 "-1" ),所以我们可以从这个区间中的所有点连一条边到 x,跑完拓扑排序即可得到答案(如果图有环也输出 "-1" )。但是,普通的建图方式是 O(n2),这显然不够优秀,题解跟我们介绍了一种用线段树优化的建图方法:建一棵线段树,将哈希表中所有的数作为叶子结点,从所有的子结点往父节点连一条边。若要将一个区间中的数连到 x ,只需将这个区间对应的所有父结点连到 x 即可,复杂度 O(log n)。
AC代码:
#include <bits/stdc++.h>
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
typedef long long LL;
const int INF=0x3f3f3f3f;
const int MAXN=2e5+5;
vector G[MAXN*6];
struct Point{
int du,num,id;
friend bool operator <(const Point a,const Point b){
return a.num>b.num;
}
}pt[MAXN*6];
int a[MAXN];
bool flag[MAXN<<2];
int tree[MAXN<<2],ind;
void pushup(int rt){
G[tree[rt<<1]].push_back(tree[rt]);
G[tree[rt<<1|1]].push_back(tree[rt]);
pt[tree[rt]].du+=2;
flag[rt]=flag[rt<<1]||flag[rt<<1|1];
}
void build(int l,int r,int rt){
if(l==r){
tree[rt]=l;
G[tree[rt]].clear();
pt[tree[rt]].du=0;
pt[tree[rt]].num=a[l];
pt[tree[rt]].id=l;
if(a[l]<0) flag[rt]=true;
else flag[rt]=false;
return;
}
tree[rt]=ind++;
G[tree[rt]].clear();
pt[tree[rt]].du=0;
pt[tree[rt]].num=-2;
pt[tree[rt]].id=tree[rt];
int m=(l+r)/2;
build(lson);
build(rson);
pushup(rt);
}
bool add(int L,int R,int to,int l,int r,int rt){
if(L<=l&&r<=R){
G[tree[rt]].push_back(to);
pt[to].du++;
return flag[rt];
}
int m=(l+r)/2;
bool ret=false;
if(L<=m) ret=ret||add(L,R,to,lson);
if(m<R) ret=ret||add(L,R,to,rson);
return ret;
}
priority_queue que;
int ans[MAXN];
int main(){
int mod,T;
scanf("%d",&T);
while(T--){
while(!que.empty()) que.pop();
scanf("%d",&mod);
int have=0;
for(int i=0;i<mod;i++){
scanf("%d",&a[i]);
if(a[i]>=0) have++;
}
ind=mod;
build(0,mod-1,1);
bool temp=false;
for(int i=0;i<mod;i++){
if(a[i]>=0){
int pos=a[i]%mod;
if(pos<i)
temp=add(pos,i-1,i,0,mod-1,1);
else if(pos>i){
if(i>0)
temp=temp||add(0,i-1,i,0,mod-1,1);
temp=temp||add(pos,mod-1,i,0,mod-1,1);
}
if(temp){
puts("-1");
break;
}
}
}
if(temp) continue;
for(int i=0;i<ind;i++){
if(pt[i].du==0)
que.push(pt[i]);
}
Point now;
int cnt=0;
while(!que.empty()){
now=que.top();
que.pop();
if(now.num<0){
for(int i=0;i<G[now.id].size();i++){
int v=G[now.id][i];
pt[v].du--;
if(pt[v].du==0) que.push(pt[v]);
}
}
else{
ans[cnt++]=now.num;
for(int i=0;i<G[now.id].size();i++){
int v=G[now.id][i];
pt[v].du--;
if(pt[v].du==0) que.push(pt[v]);
}
}
}
if(cnt<have)
puts("-1");
else if(cnt==0)
puts("");
else{
printf("%d",ans[0]);
for(int i=1;i<cnt;i++){
printf(" %d",ans[i]);
}puts("");
}
}
return 0;
}
查看7道真题和解析