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;
}
原文地址:https://www.cnblogs.com/clno1/p/11410761.html