bzoj4388: JOI2012 invitation (segment tree + heap)

The topic is here
Code Question. .

meaning of the title

have n a boy, m a girl. give k relationships, each of the form a i , b i , c i , d i , t i ,Express [ a i , b i ] boys and [ c i , d i ] of girls are good friends, and the happiness index is t i . Now choose a boy C Join a set, then select one at a time the best friends of the people in the set to add to the set, and 权值+=他们的幸福指数until all are selected. Ask how to choose to make the happiness index and maximum. If it is not possible to select everyone to export -1.

practice

It is observed that the title is actually simulating the process of a prim to find the maximum spanning tree. Consider optimizing this prim with a data structure.

First discretize, the weights between the key points and the maximum value can be directly maintained by the line segment tree, and then all points are reduced to 4n key points.

Open two line segment trees to maintain all points that are not in the set, and the edges they connect to.

The former can save a point that has not been selected on the far right of the interval, and if all the numbers in the interval are selected, it is 0;

The latter can open a linked list for each node of the segment tree.

Assume S is the set of selected points, T for the set of unselected points, maintained with a heap S T The maximum happiness index of , saves the number of that relationship.

Every time the top of the heap is popped, use this relationship to keep updating until it can't be updated.

Pay attention to some details and have corresponding comments in the code.

code

#include<bits/stdc++.h>
#define rep(i,x,y) for (int i=(x); i<=(y); i++)
#define N 131072
#define M 2097152
#define ll long long
#define pii pair<int,int>
#define lc (o<<1)
#define rc (o<<1|1)
using namespace std;
ll read(){
    char ch=getchar(); ll x=0; int op=1;
    for (; !isdigit(ch); ch=getchar()) if (ch=='-') op=-1;
    for (; isdigit(ch); ch=getchar()) x=(x<<1)+(x<<3)+ch-'0';
    return x*op;
}
int n1,C,seq[N<<1],val[M]; ll ans; bool del[N];
void gg(){
    puts("-1"); exit(0);
}
priority_queue<pii> q;
struct node{ int a,b,c,d,t; }d[N];
void cmax(int &x,int y){
    if (y>x) x=y;
}
struct seg{
    int n,m,cnt,b[N<<1],val[M],head[M];
    seg(){
        cnt=0; m=0;
        memset(head,0,sizeof(head));
    }
    struct linker{
        int to,nxt;
    }e[M];
    void add(int x,int y){
        b[++m]=x; b[++m]=y;
    }
    void pre(){
        b[++m]=1; b[++m]=n; sort(b+1,b+1+m);
        int m_=m; m=0;
        rep (i,1,m_) if (!m || b[i]!=b[m]) b[++m]=b[i];
    }
    void get(int &x,int &y){
        x=lower_bound(b+1,b+1+m,x)-b;
        y=lower_bound(b+1,b+1+m,y)-b;
    }
    void cal(){
        rep (i,1,m-1) if (b[i+1]-b[i]-1){
            if (!seq[i]) gg();
            ans+=(ll)seq[i]*(b[i+1]-b[i]-1);
        }
    }
    void build(int o,int l,int r){
        val[o]=r; if (l==r) return;
        int mid=l+r>>1;
        build(lc,l,mid); build(rc,mid+1,r);
    }
    void ins(int o,int l,int r,int x,int y,int z){
        if (x<=l && r<=y){
            e[++cnt].to=z; e[cnt].nxt=head[o]; head[o]=cnt;
            return;
        }
        int mid=l+r>>1;
        if (x<=mid) ins(lc,l,mid,x,y,z);
        if (y>mid) ins(rc,mid+1,r,x,y,z);
    }
    void change(int o,int l,int r,int p){
        for (int &i=head[o]; i; i=e[i].nxt){//一定要加‘&’!这样才不会重复遍历。
            int v=e[i].to;
            if (!del[v]){
                q.push(make_pair(d[v].t,v));
                del[v]=1;
            }
        }
        if (l==r){ val[o]=0; return; }
        int mid=l+r>>1;
        if (p<=mid) change(lc,l,mid,p); else change(rc,mid+1,r,p);
        val[o]=max(val[lc],val[rc]);
    }
    int ask(int o,int l,int r,int x,int y){
        if (x<=l && r<=y) return val[o];
        int mid=l+r>>1,ret=0;
        if (x<=mid) cmax(ret,ask(lc,l,mid,x,y));
        if (y>mid) cmax(ret,ask(rc,mid+1,r,x,y));
        return ret;
    }
}A,B;//A,B存的是所有未在集合中的点,以及他们连出去的边
void build(int o,int l,int r){
    val[o]=0; if (l==r) return;
    int mid=l+r>>1;
    build(lc,l,mid); build(rc,mid+1,r);
}
void change(int o,int l,int r,int x,int y,int v){
    if (x<=l && r<=y){
        cmax(val[o],v); return;//标记永久化
    }
    int mid=l+r>>1;
    if (x<=mid) change(lc,l,mid,x,y,v);
    if (y>mid) change(rc,mid+1,r,x,y,v);
}
void dfs(int o,int l,int r){
    if (l==r){ seq[l]=val[o]; return; }
    int mid=l+r>>1;
    cmax(val[lc],val[o]); cmax(val[rc],val[o]);
    dfs(lc,l,mid); dfs(rc,mid+1,r);
}
int main(){
    A.n=read(); B.n=read(); C=read();
    n1=read();
    rep (i,1,n1){
        d[i].a=read(); d[i].b=read(); d[i].c=read(); d[i].d=read(); d[i].t=read();
        A.add(d[i].a,d[i].b); B.add(d[i].c,d[i].d);
    }
    A.pre();//离散化
    rep (i,1,n1) A.get(d[i].a,d[i].b);
    build(1,1,A.m);
    rep (i,1,n1) if (d[i].a<d[i].b) change(1,1,A.m,d[i].a,d[i].b-1,d[i].t);
    dfs(1,1,A.m); A.cal();
    B.pre();//离散化
    rep (i,1,n1) B.get(d[i].c,d[i].d);
    build(1,1,B.m);
    rep (i,1,n1) if (d[i].c<d[i].d) change(1,1,B.m,d[i].c,d[i].d-1,d[i].t);
    dfs(1,1,B.m); B.cal();
    //以上处理了相邻关键点之间的权值
    A.build(1,1,A.m); B.build(1,1,B.m);
    rep (i,1,n1){
        A.ins(1,1,A.m,d[i].a,d[i].b,i);//建立每个点对应的关系
        B.ins(1,1,B.m,d[i].c,d[i].d,i);
    }
    A.change(1,1,A.m,C);
    while (!q.empty()){
        int x=q.top().second,y; q.pop();
        if (y=A.ask(1,1,A.m,d[x].a,d[x].b)){
            ans+=d[x].t; A.change(1,1,A.m,y);
            q.push(make_pair(d[x].t,x));//一直要push进去,直到没有可以更新的人为止
            continue;
        }
        if (y=B.ask(1,1,B.m,d[x].c,d[x].d)){
            ans+=d[x].t; B.change(1,1,B.m,y);
            q.push(make_pair(d[x].t,x));
        }
    }
    if (A.val[1] || B.val[1]) gg();
    printf("%lld\n",ans);
    return 0;
}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325940244&siteId=291194637