牛客多校第四场 J.Hash Function(线段树优化建图+拓扑排序)

题目传送门:https://www.nowcoder.com/acm/contest/142/J

题意:给一个hash table,求出字典序最小的插入序列,或者判断不合法。

分析:

eg.对于序列{7,8,16},插入后为{16, -1, -1, -1, -1, -1, -1, 7, 8}。(即,依次插入7,8,16。而插入16时发现7已经被占,所以依次考虑(h(x)+1)%n ,因此16放在0的位置上。)这是正向插入,问题是给一个最终序列,问插入序列。

通过对hash表的观察可以得到:

一个区间里的数一定比单独一个数插入更早。

 

1.存在答案:

那么就会存在对于每一个数a[i],存在两个位置s=a[i]%n,即本应该放在的位置。和t=i,即实际放在的位置。

 

朴素O(n^2)建图:

每找到一个数字s!=t,那么向前建边。若s==t,不需要建边。然后每次选择度数为0的点中最小的数(保证字典序min),然后把与该点相连的所有边删去。

 

通过上述朴素建图,发现每个点所建边的是一段区间内的所有点。引出:

线段树O(n)优化建图:

同上,若一个点需要连向一个区间,就向线段树上的这个区间连边。然后把度数为0的点一一删去,即把线段树内对应的叶子节点清空,然后向上更新。当一个区间为空时,就把所有连向这个点的所有边删掉了。

ps.一个点最多会向线段树上logn个区间,即logn个点相连。

 

2.判断不合法:

在区间[s,t)内存在-1,即序列不合法。

或拓扑排序出现环。

 

  1 #include <bits/stdc++.h>
  2 #define maxn 200005
  3 using namespace std;
  4 typedef pair<int,int> pii;
  5 int fix[maxn],a[maxn];
  6 int pos[maxn<<2],id[maxn<<2];
  7 int deg[maxn<<2];
  8 vector<int> G[maxn<<2]; 
  9 int n;
 10 void init(int n){
 11     memset(deg,0,sizeof(int)*(n<<2|5));
 12     for (int i=0;i<(n<<2|5);i++) G[i].clear();
 13 }
 14 void addedge(int u,int v){
 15     G[u].push_back(v);
 16     deg[v]++;
 17 }
 18 void build(int root,int l,int r){
 19     id[root]=-1;
 20     if (l==r){
 21         pos[l]=root;
 22         id[root]=l;
 23         return ;
 24     }
 25     int mid=(l+r)/2;
 26     addedge(root<<1,root);
 27     addedge(root<<1|1,root);
 28     build(root<<1,l,mid);
 29     build(root<<1|1,mid+1,r); 
 30 }
 31 int judge(int s,int t){
 32     if (s<=t) return (fix[t]-fix[s]==0) && (a[s]!=-1);
 33     else return (fix[n-1]-fix[s-1]==0) && !fix[t];
 34 }
 35 void Addedge(int L,int R,int p,int root,int l,int r){
 36     if (L<=l && r<=R){
 37         addedge(root,p);
 38         return ;
 39     }
 40     int mid=(l+r)/2;
 41     if (L<=mid) Addedge(L,R,p,root<<1,l,mid);
 42     if (R>mid) Addedge(L,R,p,root<<1|1,mid+1,r);
 43 }
 44 void topo(){
 45     priority_queue<pii,vector<pii>,greater<pii> > Q;
 46     for (int i=0;i<n;i++)
 47         if (!deg[pos[i]]) Q.push({a[i],pos[i]});
 48     vector<int> ans;
 49     while (!Q.empty()){
 50         pii pos=Q.top();
 51         Q.pop();
 52         int u=pos.second;
 53         if (pos.first!=-1) ans.push_back(pos.first);
 54         int v;
 55         for (auto v : G[u]){
 56             if (--deg[v]==0){
 57                 if (id[v]==-1) Q.push({-1,v});
 58                 else Q.push({a[id[v]],v});
 59             }
 60         }
 61     }
 62     if (ans.size()!=n-fix[n-1]){
 63         cout << -1 << endl;
 64         return ;
 65     }
 66     if (ans.size()==0){
 67         cout << endl;
 68         return ;
 69     }
 70     for (int i=0;i<ans.size();i++){
 71         if (i==0) cout << ans[i];
 72         else cout << " " << ans[i];
 73     }
 74     cout << endl;
 75     return ;
 76 }
 77 int main(){
 78     int t;
 79     cin >> t;
 80     while (t--){
 81         cin >> n;
 82         init(n);
 83         for (int i=0;i<n;i++){
 84             cin >> a[i];
 85             if (i) fix[i]=fix[i-1]+(a[i]==-1);
 86             else fix[i]=(a[i]==-1);
 87         }
 88         int flag=0;
 89         for (int i=0;i<n;i++){
 90             if (a[i]!=-1 && !judge(a[i]%n,i)){
 91                 cout << -1 << endl;
 92                 flag=1;
 93                 break;
 94             }
 95         }
 96         if (flag) continue;
 97         build(1,0,n-1);
 98         for (int i=0;i<n;i++){
 99             if (a[i]!=-1){
100                 int s=a[i]%n,t=i;
101                 if (s==t) continue;
102                 if (s<t){
103                     Addedge(s,t-1,pos[i],1,0,n-1);
104                 }
105                 else{
106                     if (t) Addedge(0,t-1,pos[i],1,0,n-1);
107                     Addedge(s,n-1,pos[i],1,0,n-1);
108                 }
109             }
110         }
111         topo();
112     }
113     return 0;
114 }

 

 

猜你喜欢

转载自www.cnblogs.com/changer-qyz/p/9385674.html