hdu 5764 After a Sleepless Night(2016多校第四场1002) 线段树

来源:互联网 发布:unity3d里字母 编辑:程序博客网 时间:2024/05/17 07:07

显然对于值为n的点一定构成链,然后我们只需要把两端最小的点作为根(为了字典序),然后就好办了,对于每棵子树根一定是最大值,然后最大值也一定形成链,这样我们就能把所有能确定的点确定下来(根的底端),然后不能确定的点的值一定小于等于输入的全值,下面介绍个人的处理方法:

我们从没有分配的最小的权值开始,因为字典序所以要分配给序号小的点,那么怎么办,我们可以先把所有未分配的店按输入的权值从小到大排序,对于每个点看看输入权值之前能分配多少个权值,如果分配个数大于这个点之前没有分配的点的数量,那么就能从这个点的后面取点扔到这个点的前面,用线段树维护即可。

#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>#include<vector>#pragma comment(linker, "/STACK:102400000,102400000")using namespace std;const int maxn=100005;vector<int>g[maxn];int vis[maxn];int use[maxn];int a[maxn];int in[maxn];int ans[maxn];int s[maxn];int fa[maxn];int find(int pa){    if(fa[pa]==-1||fa[pa]==pa) return fa[pa]=pa;    return fa[pa]=find(fa[pa]);}void init(int n){    for(int i=0;i<=n;i++){        vis[i]=0;        in[i]=0;        fa[i]=-1;        use[i]=0;        ans[i]=0;        g[i].clear();    }}int flag;void dfs(int u,int pa){    int cnt=0;    for(int v:g[u]){        if(v!=pa){            if(a[v]>a[u]){                flag=1;                return;            }            if(a[v]==a[u]){                cnt++;            }        }    }    if(cnt>1){        flag=1;        return;    }    if(cnt==0){        ans[u]=a[u];        if(use[a[u]]){            flag=1;            return;        }        use[a[u]]=1;    }    for(int v:g[u]){        if(v!=pa)            dfs(v,u);    }}int x[maxn],y[maxn],to[maxn];int cmp(int x,int y){    if(a[x]!=a[y]) return a[x]<a[y];    return x<y;}struct pi{    int le,ri;    int m1;    int m2;    int lazy;}pp[maxn<<2];void build(int tot,int l,int r){    pp[tot].le=l;    pp[tot].ri=r;    pp[tot].lazy=0;    if(l==r){        pp[tot].m1=x[l];        pp[tot].m2=s[a[x[l]]]-l;        return;    }    build(2*tot,l,(l+r)/2);    build(2*tot+1,(l+r)/2+1,r);    pp[tot].m1=min(pp[2*tot].m1,pp[2*tot+1].m1);    pp[tot].m2=min(pp[2*tot].m2,pp[2*tot+1].m2);}void merg1(int tot,int x){    if(pp[tot].le==pp[tot].ri){        pp[tot].m1=1000000000;        return;    }    int mid=(pp[tot].le+pp[tot].ri)/2;    if(x<=mid) merg1(2*tot,x);    else merg1(2*tot+1,x);    pp[tot].m1=min(pp[2*tot].m1,pp[2*tot+1].m1);}void merg2(int tot,int l,int r,int la){    if(l>r) return;    if(pp[tot].le>=l&&pp[tot].ri<=r){        pp[tot].lazy+=la;        return;    }    int mid=(pp[tot].le+pp[tot].ri)/2;    if(l<=mid) merg2(2*tot,l,r,la);    if(r>mid) merg2(2*tot+1,l,r,la);    pp[tot].m2=min(pp[2*tot].m2+pp[2*tot].lazy,pp[2*tot+1].m2+pp[2*tot+1].lazy);}int query(int tot,int all){    if(all+pp[tot].lazy+pp[tot].m2>0) return pp[tot].ri+1;    if(pp[tot].le==pp[tot].ri) return pp[tot].le;    all+=pp[tot].lazy;    int s= query(2*tot,all);    if(s<=pp[2*tot].ri) return s;    return query(2*tot+1,all);}int query1(int tot,int l,int r){    if(pp[tot].le>=l&&pp[tot].ri<=r) return pp[tot].m1;    int s=1000000000;    int mid=(pp[tot].le+pp[tot].ri)/2;    if(l<=mid) s=min(s,query1(2*tot,l,r));    if(r>mid) s=min(s,query1(2*tot+1,l,r));    return s;}int main(){    int t,N=0;    cin>>t;    while(t--){        int n;        scanf("%d",&n);        init(n);        for(int i=1;i<=n;i++) scanf("%d",&a[i]);        for(int i=1;i<n;i++){            int x,y;            scanf("%d%d",&x,&y);            g[x].push_back(y);            g[y].push_back(x);        }        for(int i=1;i<=n;i++){            if(a[i]==n){                vis[i]=1;            }        }        for(int i=1;i<=n;i++){            if(!vis[i]) continue;            for(int v:g[i]){                if(vis[v]){                    fa[find(i)]=find(v);                    if(i<v){                        in[i]++;                        in[v]++;                    }                }            }        }        int all=0;        flag=0;        for(int i=1;i<=n;i++){            if(vis[i]){                if(all==0){                    all=find(i);                }                else{                    if(all!=find(i)){                        flag=1;                    }                }            }        }        if(all==0) flag=1;        if(flag){            printf("Case #%d: Impossible\n",++N);            continue;        }        for(int i=1;i<=n;i++){            if(vis[i]){                if(in[i]>2){                    flag=1;                }            }        }        if(flag){            printf("Case #%d: Impossible\n",++N);            continue;        }        int root=0;        for(int i=1;i<=n;i++){            if(vis[i]){                if(in[i]==1||in[i]==0){                    root=i;                    break;                }            }        }        dfs(root,-1);        if(flag){            printf("Case #%d: Impossible\n",++N);            continue;        }        int tot=0;        for(int i=1;i<=n;i++){            if(ans[i]==0) x[++tot]=i;        }        if(tot==0){            printf("Case #%d:",++N);            for(int i=1;i<=n;i++) printf(" %d",ans[i]);            printf("\n");            continue;        }        sort(x+1,x+tot+1,cmp);        tot=0;        for(int i=1;i<=n;i++){            s[i]=s[i-1];            if(use[i]==0){ y[++tot]=i;                s[i]++;            }        }        for(int i=1;i<=tot;i++){            if(s[a[x[i]]]<i){                flag=1;                break;            }        }        if(flag){            printf("Case #%d: Impossible\n",++N);            continue;        }        for(int i=1;i<=tot;i++) to[x[i]]=i;        build(1,1,tot);        for(int i=1;i<=tot;i++){            int w=query(1,0);            if(w>tot){                w=query1(1,1,tot);                ans[w]=y[i];            }            else{                int w1=query1(1,1,w);                ans[w1]=y[i];                w=w1;            }            merg1(1,to[w]);            merg2(1,1,to[w]-1,-1);            merg2(1,to[w],to[w],1000000000);        }        printf("Case #%d:",++N);        for(int i=1;i<=n;i++) printf(" %d",ans[i]);        printf("\n");    }}


0 0
原创粉丝点击