竞赛讨论区 > 记录一下学到的新姿势:线段树优化建图
头像
Blogggggg
编辑于 2018-07-31 01:49
+ 关注

记录一下学到的新姿势:线段树优化建图

题目大意:
已知哈希函数为 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;
}

全部评论

(0) 回帖
加载中...
话题 回帖

等你来战

查看全部

热门推荐