zoukankan      html  css  js  c++  java
  • 洛谷 P1084 疫情控制 —— 二分+码力

    题目:https://www.luogu.org/problemnew/show/P1084

    5个月前曾经写过一次,某个上学日的深夜,精疲力竭后只有区区10分,从此没管...

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    #define ll long long
    using namespace std;
    priority_queue< pair<int,int> >q1,q2;
    int const MAXN=50005;
    int n,m,head[MAXN],ct,ans,fa[MAXN],sid[MAXN],lf,lef[MAXN],gr[MAXN];
    ll l,r;
    bool vis[MAXN],in[MAXN];
    struct N{
        int to,next,w;
        N(int t=0,int n=0,int w=0):to(t),next(n),w(w) {}
    }edge[MAXN<<1];
    struct E{
        int st,pos;
        ll rest;
    }am[MAXN];
    void add(int x,int y,int z)
    {
        edge[++ct]=N(y,head[x],z);head[x]=ct;
        edge[++ct]=N(x,head[y],z);head[y]=ct;
    }
    void ps(int x)
    {
        int nw=am[x].st;
        while(fa[nw]!=1&&am[x].rest-sid[nw])
        {
            am[x].rest-=sid[nw];
            nw=fa[nw];
        }
        if(fa[nw]==1&&am[x].rest>=2*sid[nw])am[x].pos=1,am[x].rest-=sid[nw];
        else am[x].pos=nw;
    }
    void init(int x,int f,int g,int w)//fa,gr,lef,sid
    {
        int t=0;
        fa[x]=f;sid[x]=w;
        if(g==1)gr[x]=x;
        else gr[x]=g;
        for(int i=head[x],u;i;i=edge[i].next)
        {
            u=edge[i].to;
            if(u==f)continue;
            init(u,x,gr[x],edge[i].w);t++;
        }
        if(!t)lef[++lf]=x;
    }
    void dfs(int x)
    {
        vis[x]=1;
        for(int i=head[x],u;i;i=edge[i].next)
            if(edge[i].to!=fa[x])dfs(edge[i].to);
    }
    bool pd(ll mid)
    {
    //    printf("mid=%d
    ",mid);
        memset(vis,0,sizeof vis);
        memset(in,0,sizeof in);
        while(q1.size())q1.pop();
        while(q2.size())q2.pop();
        for(int i=1;i<=m;i++)
        {
            am[i].rest=mid;
            ps(i);
            if(am[i].pos!=1)dfs(am[i].pos);
            q1.push(make_pair(-am[i].rest,i));
        }
    //    for(int i=1;i<=m;i++)
    //        printf("am[%d].pos=%d
    ",i,am[i].pos);
        for(int i=1;i<=lf;i++)
            if(!vis[lef[i]]&&!in[gr[lef[i]]])
            {
                q2.push(make_pair(-sid[gr[lef[i]]],gr[lef[i]]));
                in[gr[lef[i]]]=1;
            }
    //    printf("q1:%d q2:%d
    ",q1.size(),q2.size());
        while(q1.size()&&q2.size())
        {
            int x=q1.top().second;q1.pop();//am
            int y=q2.top().second;q2.pop();//gr
    //        printf("x=%d y=%d
    ",x,y);
            while(am[x].rest<sid[gr[y]]&&q1.size())x=q1.top().second,q1.pop();
            if(am[x].rest<sid[gr[y]]&&!q1.size())return 0;
        }
        
        if(q2.size())return 0;
        else return 1;
    }
    int main()
    {
        scanf("%d",&n);
        for(int i=1,x,y,z;i<n;i++)
        {
            scanf("%d%d%d",&x,&y,&z);
            add(x,y,z);r+=z;
        }
        init(1,0,1,0);
    //    for(int i=1;i<=lf;i++)
    //        printf("lef[%d]=%d
    ",i,lef[i]);
        scanf("%d",&m);
        for(int i=1;i<=m;i++)
            scanf("%d",&am[i].st);
        ans=-1;
        while(l<=r)
        {
            ll mid=((l+r)>>1);
    //        cout<<ans<<endl;
            if(pd(mid))ans=mid,r=mid-1;
            else l=mid+1;
        }
        printf("%d",ans);
        return 0;
    }
    囧1

    这几天又重新写它了,自信码力已和当时不可同日而语,于是又写了一遍,然而仅仅20分,改了改成了30分...

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    #include<vector>
    using namespace std;
    typedef long long ll;
    int const xn=50005;
    int n,m,cnt,hd[xn],ct,to[xn<<1],nxt[xn<<1],w[xn<<1],rs[xn],lf[xn],rk[xn];
    int f[xn][20],son[xn],dep[xn],num[xn];
    ll dis[xn],sum,ans;
    bool vis[xn],use[xn];
    priority_queue<int>q;
    vector<int>v[xn];
    struct N{
        int st,pos; ll tim;
        bool operator < (const N &y) const
            {return tim<y.tim;}
    }a[xn];
    int rd()
    {
        int ret=0,f=1; char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=0; ch=getchar();}
        while(ch>='0'&&ch<='9')ret=(ret<<3)+(ret<<1)+ch-'0',ch=getchar();
        return f?ret:-ret;
    }
    void add(int x,int y,int z){to[++ct]=y; nxt[ct]=hd[x]; w[ct]=z; hd[x]=ct;}
    int dfs(int x,int fa,int r)
    {
        int ret=0,fl=0; f[x][0]=fa; 
        for(int i=1;i<=16;i++)f[x][i]=f[f[x][i-1]][i-1];
        for(int i=hd[x],u;i;i=nxt[i])
        {
            if((u=to[i])==fa)continue;
            fl=1;
            dis[u]=dis[x]+w[i]; dep[u]=dep[x]+1;
            if(x==1)lf[u]+=dfs(u,x,u),son[++cnt]=u;
            else ret+=dfs(u,x,r);
        }
        if(!fl)ret=1,rs[x]=r;
        return ret;
    }
    bool cmp(int a,int b){return dis[son[a]]>dis[son[b]];}
    void dfs2(int x)
    {
        bool fl=0;
        for(int i=hd[x],u;i;i=nxt[i])
            if((u=to[i])!=f[x][0])fl=1,dfs2(u);
        if(!fl)num[rs[x]]++;
    }
    bool ck(int mid)
    {
        memset(vis,0,sizeof vis);
        memset(num,0,sizeof num);
        memset(use,0,sizeof use);
        for(int i=1;i<=cnt;i++)v[i].clear();
        while(q.size())q.pop();
        for(int i=1;i<=m;i++)a[i].pos=0;
        for(int i=1;i<=m;i++)
        {
            int x=a[i].st; ll ret=mid;
            for(int j=16;j>=0;j--)
                if(f[x][j]>1&&dis[x]-dis[f[x][j]]<=ret)
                    ret-=dis[x]-dis[f[x][j]],x=f[x][j];
            if(dep[x]>1||(dep[x]==1&&ret<dis[x]))dfs2(x);
            else
            {
                a[i].pos=x; a[i].tim=ret-dis[x];
                q.push(i); //x:1~n
                v[x].push_back(i);
    //            printf("in:%d
    ",i);//tim从大到小
            }
        }
        for(int i=1;i<=cnt;i++)
            if(num[son[i]]==lf[son[i]])vis[i]=1;//i != son[i]   // vis[1~cnt]
        for(int i=1;i<=cnt;i++)
        {
            int x=rk[i];//1~cnt
    //        printf("vis[%d]=%d
    ",son[x],vis[x]);
            if(vis[x])continue;
            if(!q.size())return 0;
            int k=q.top(); q.pop();
            while(use[k])k=q.top(),q.pop();
            if(a[k].tim<dis[son[x]])
            {
                int us=-1;
                for(int j=0;j<v[son[x]].size();j++)
                {
                    int nw=v[son[x]][j];
                    if(!use[nw]&&(us==-1||a[nw].tim<a[us].tim))us=nw;
                }
                if(us==-1)return 0;
                else use[us]=1,q.push(k);
            }
            vis[x]=1;
    //        printf("%d -> %d
    ",i,son[x]);
        }
    //    printf("return 1
    ");
        return 1;
    }
    int main()
    {
        n=rd();
        for(int i=1,x,y,z;i<n;i++)
        {
            x=rd(); y=rd(); z=rd();
            add(x,y,z); add(y,x,z);
            sum+=z;
        }
        m=rd();
        for(int i=1;i<=m;i++)a[i].st=rd();
        dfs(1,0,0);
        for(int i=1;i<=cnt;i++)rk[i]=i;
        sort(rk+1,rk+cnt+1,cmp);//rk -> 1~cnt
    //    for(int i=1;i<=cnt;i++)printf("dis[%d]=%lld rk[%d]=%d
    ",son[i],dis[son[i]],i,rk[i]);
        ll l=0,r=sum; ans=-1;
        while(l<=r)
        {
            ll mid=((l+r)>>1ll);
    //        printf("l=%lld r=%lld mid=%lld
    ",l,r,mid);
            if(ck(mid))ans=mid,r=mid-1;
            else l=mid+1;
        }
        printf("%lld
    ",ans);
        return 0;
    }
    囧2

    然后又去参考了TJ...看到思路和我的一样,但是代码简洁很多...

    于是改改改,然后和模仿的那篇TJ拍拍拍,居然拍出了TJ的错...又和另一篇TJ拍拍拍,大数据又有错...

    不管了直接交上去,就A了...

    然后发现数据生成没管军队不在根上,但第一篇TJ小数据真的错了...

    和 Narh 的代码拍,大数据又有错...但是数据那么大怎么改...不管了(反正也A了)...

    又练习码力了,没事不要多写什么 queue 啦, vector 啦,直接排个序就好了。

    代码如下:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    int const xn=50005;
    int n,m,hd[xn],ct,to[xn<<1],nxt[xn<<1],w[xn<<1],dis[xn],sum,ans;
    int f[xn][20],num[xn],mn[xn],cnta,cnts,st[xn];
    bool vis[xn],use[xn];
    struct N{
        int id,tim;
        bool operator < (const N &y) const
            {return tim>y.tim;}
    }a[xn],son[xn];
    int rd()
    {
        int ret=0,f=1; char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=0; ch=getchar();}
        while(ch>='0'&&ch<='9')ret=(ret<<3)+(ret<<1)+ch-'0',ch=getchar();
        return f?ret:-ret;
    }
    void add(int x,int y,int z){to[++ct]=y; nxt[ct]=hd[x]; w[ct]=z; hd[x]=ct;}
    void dfs(int x,int fa,int r)
    {
        int ret=0; f[x][0]=fa; 
        for(int i=1;i<=16;i++)f[x][i]=f[f[x][i-1]][i-1];
        for(int i=hd[x],u;i;i=nxt[i])
        {
            if((u=to[i])==fa)continue;
            dis[u]=dis[x]+w[i];    dfs(u,x,r);
        }
    }
    bool dfs2(int x)
    {
        bool fl=1,bj=1;
        if(vis[x])return 1;
        for(int i=hd[x],u;i;i=nxt[i])
        {
            if((u=to[i])==f[x][0])continue; bj=0;
            bool k=dfs2(u);
            if(!k)
            {
                fl=0;
                if(x==1)son[++cnts].id=u,son[cnts].tim=dis[u];
            }
        }
        if(bj)return 0;
        return fl;
    }
    bool ck(int mid)
    {
        memset(vis,0,sizeof vis);
        memset(use,0,sizeof use);
        memset(mn,0,sizeof mn);
        cnta=0; cnts=0;
        for(int i=1;i<=m;i++)
        {
            int x=st[i]; ll ret=mid;
            for(int j=16;j>=0;j--)
                if(f[x][j]>1&&dis[x]-dis[f[x][j]]<=ret)
                    ret-=dis[x]-dis[f[x][j]],x=f[x][j];
            if(f[x][0]>1||(f[x][0]==1&&ret<dis[x]))vis[x]=1;
            else
            {
                a[++cnta].id=i; a[cnta].tim=ret-dis[x];//-dis[x]
                if(!mn[x]||a[cnta].tim<a[mn[x]].tim)mn[x]=i;//mn[1~n]=(1~m)
            }
        }
        if(dfs2(1))return 1;
        sort(a+1,a+cnta+1); sort(son+1,son+cnts+1);
        for(int i=1,p=1;i<=cnts;i++)
        {
            int nw=son[i].id;
            if(mn[nw]&&!use[mn[nw]]){use[mn[nw]]=1; continue;}//优先用小的,不用考虑其它儿子是因为从大往小用
            while(p<=cnta&&use[a[p].id])p++;
            if(p>cnta||a[p].tim<son[i].tim)return 0;
            use[a[p].id]=1;
        }
        return 1;
    }
    int main()
    {
        n=rd();
        for(int i=1,x,y,z;i<n;i++)
        {
            x=rd(); y=rd(); z=rd();
            add(x,y,z); add(y,x,z);
            sum+=z;
        }
        m=rd();
        for(int i=1;i<=m;i++)st[i]=rd();
        dfs(1,0,0);
        int l=0,r=sum; ans=-1;
        while(l<=r)
        {
            int mid=((l+r)>>1ll);
            if(ck(mid))ans=mid,r=mid-1;
            else l=mid+1;
        }
        printf("%d
    ",ans);
        return 0;
    }
  • 相关阅读:
    mysql--连接查询(内外连接)
    Mysql--select基础查询
    Mysql--数据定义语言(DDL)
    Mysql--数据操作语言(DML)
    java--String、StringBuilder、StringBuffer的解析和比较?
    Java--equals和 == 的比较和equals()、HashCode()的重写
    Mysql--数据类型
    Mysql--约束
    SpringCloud版本说明
    springBoot 发送邮件
  • 原文地址:https://www.cnblogs.com/Zinn/p/9690031.html
Copyright © 2011-2022 走看看