• Educational Codeforces Round 69 E


    题意:有n个空心物品,每个物品有外部体积outi和内部体积ini,如果ini>outj,那么j就可以套在i里面。现在我们要选出n个物品的一个子集,这个子集内的k个物品全部套在一起,且剩下的物品都无法添加到这个子集中(没有空间塞进去)。

    定义浪费的空间为子集中空心的部分,即ini1+(ini2outi1)+(ini3outi2)++(inikoutik1)ini1+(ini2−outi1)+(ini3−outi2)+⋯+(inik−outik−1)。求浪费空间最少的子集个数。

    解法:第一时间能想到最短路计数,但是朴素建图办法是n^2的。不会线段树优化建图,这里学习的是https://www.cnblogs.com/birchtree/p/11274812.html这位大佬的。

    上面大佬的博客说得十分好了。线段树优化的原理其实就是通过一棵线段树当作工具树,这棵树不附带信息,只是作为一个桥梁连原图结点,且因为线段树能极短地表示区间的优点使得:向区间连边时极大的优化边数。

    从而达到优化边数的目的。

    upd:好像被新数据hack了

    #include<bits/stdc++.h>
    using namespace std;
    const int N=1e6+10;
    const int MOD=1e9+7;
    int n,s,t,tot,p[N],b[N],tag[N],indeg[N],outdeg[N];
    typedef long long LL;
    struct dat{
        int l,r;
        bool operator < (const dat &rhs) const {
            return r<rhs.r;
        }
    }a[N];
    
    int cnt=0,head[N],nxt[N<<2],to[N<<2],len[N<<2];
    void add_edge(int x,int y,int z) {
        nxt[++cnt]=head[x]; to[cnt]=y; len[cnt]=z; head[x]=cnt;
        indeg[y]++; outdeg[x]++;
    }
    
    void build(int rt,int l,int r) {
        tot=max(tot,rt);
        if (l==r) {
            p[l]=rt;
            return;
        }
        int mid=l+r>>1;
        add_edge(rt,rt<<1,0); add_edge(rt,rt<<1|1,0);
        build(rt<<1,l,mid);
        build(rt<<1|1,mid+1,r);
    }
    
    void query(int rt,int l,int r,int ql,int qr,int i) {
        if (ql<=l && r<=qr) {
            add_edge(tot+i,rt,a[i].l);
            return;
        }
        int mid=l+r>>1;
        if (ql<=mid) query(rt<<1,l,mid,ql,qr,i);
        if (qr>mid) query(rt<<1|1,mid+1,r,ql,qr,i);
    }
    
    queue<int> q;
    LL dis[N],ans[N];
    LL toposort() {
        memset(dis,0x3f,sizeof(dis));
        memset(ans,0,sizeof(ans));
        for (int i=1;i<=n;i++) {
            tag[i]+=tag[i-1];
            if (tag[i]==0) add_edge(s,tot+i,0);
            else add_edge(p[i],tot+i,-a[i].r);
        }
        q.push(s); dis[s]=0; ans[s]=1;
        add_edge(s,1,0x3f3f3f3f);
        while (!q.empty()) {
            int x=q.front(); q.pop();
            for (int i=head[x];i;i=nxt[i]) {
                int y=to[i];
                if (dis[x]+len[i]<dis[y]) {
                    dis[y]=dis[x]+len[i];
                    ans[y]=ans[x];
                } else if (dis[x]+len[i]==dis[y]) {
                    ans[y]=(ans[x]+ans[y])%MOD;
                }
                if (--indeg[y]==0) q.push(y);
            }
        }
        return ans[t];        
    }
    
    int main()
    {
        scanf("%d",&n);
        for (int i=1;i<=n;i++) scanf("%d%d",&a[i].r,&a[i].l);
        sort(a+1,a+n+1);
        tot=0;
        build(1,1,n);
        //for (int i=1;i<=n;i++) add_edge(p[i],tot+i,-a[i].r);
        for (int i=1;i<=n;i++) b[i]=a[i].r;
        s=0; t=tot+n+1;
        for (int i=1;i<=n;i++) {
            int tmp=upper_bound(b+1,b+i+1,a[i].l)-b-1;
            if (tmp>=1) query(1,1,n,1,tmp,i),tag[1]++,tag[tmp+1]--;
            else add_edge(tot+i,t,0);
        }
        
        cout<<toposort()<<endl;
        return 0;
    }
  • 相关阅读:
    beta冲刺——用户使用调查报告
    专业团队——Beta计划总结随笔
    专业团队测试随笔
    Beta冲刺--第十次随笔
    Beta冲刺--第九次随笔(md文档问题的解决)
    Beta冲刺--第八次随笔
    Beta冲刺--第七次随笔(仓库优化)
    Beta冲刺--第六次随笔(仓库修改)
    Beta冲刺--第五次随笔
    Beta冲刺--第四次随笔
  • 原文地址:https://www.cnblogs.com/clno1/p/11410761.html
Copyright © 2020-2023  润新知