题意:有A个男生B个女生。n个条件,第i个条件为 b1i 到 e1i 的男生和 b2i 到 e2i 的女生这些人中任意一个人都可以邀请其他人,并且通过这个关系邀请一个人的收益为 vi 。一开始男生C被邀请,求邀请到所有人的最大收益。
这就相当于一个最大生成树,因此答案和C无关。
将区间A,B分别离散化,每个离散化后的区间只需要一个点和外界相连,其他点都可以用经过这段区间的所有条件中的最大收益更新。这个东西先用线段树搞一下。
然后每个区间一个点求一个最大生成树。维护S集和T集分别为已选点集合和未选点集合。用两棵线段树分别维护A和B中在T集中的点和未选的边。
用大根堆维护横跨S,T的边,每次选出一条最大边,将对应点加入S集,并将该点的边加入堆。
#include <bits/stdc++.h>
using namespace std;
#define N 810000
#define ll long long
#define ls l,mid,now<<1
#define rs mid+1,r,now<<1|1
#define PA pair<int,int>
ll ans;
int A,B,n;
int b1[N],e1[N],b2[N],e2[N],v[N];
int vis[N];
priority_queue<PA>que;
struct tr1
{
int tr[N],st[N],cnt;
void ins(int x){st[++cnt]=x;}
void trs(int &x){x=lower_bound(st+1,st+1+cnt,x)-st;}
void cal()
{
sort(st+1,st+1+cnt);
cnt=unique(st+1,st+1+cnt)-st-1;
}
void insert(int l,int r,int now,int lq,int rq,int v)
{
if(lq<=l&&r<=rq)
{tr[now]=max(tr[now],v);return;}
int mid=(l+r)>>1;
if(mid>=lq)insert(ls,lq,rq,v);
if(mid<rq) insert(rs,lq,rq,v);
}
void down(int l,int r,int now)
{
if(l==r)
{
int t=st[l+1]-st[l]-1;
if(l!=cnt&&t)
{
if(!tr[now]){puts("-1");exit(0);}
ans+=(ll)t*tr[now];
}
return;
}
int mid=(l+r)>>1;
tr[now<<1]=max(tr[now],tr[now<<1]);
tr[now<<1|1]=max(tr[now],tr[now<<1|1]);
down(ls);down(rs);
}
}A1,B1;
struct tr2
{
int tr[N];
vector<int>vec[N];
void init(int l,int r,int now)
{
tr[now]=r;
if(l==r)return;
int mid=(l+r)>>1;
init(ls);init(rs);
}
void insert(int l,int r,int now,int lq,int rq,int v)
{
if(lq<=l&&r<=rq)
{vec[now].push_back(v);return;}
int mid=(l+r)>>1;
if(mid>=lq)insert(ls,lq,rq,v);
if(mid<rq) insert(rs,lq,rq,v);
}
void get(int l,int r,int now,int pos)
{
for(int i=0,t;i<vec[now].size();i++)
if(!vis[t=vec[now][i]])
{vis[t]=1;que.push(PA(v[t],t));}
vec[now].clear();
if(l==r){tr[now]=0;return;}
int mid=(l+r)>>1;
if(mid>=pos)get(ls,pos);
else get(rs,pos);
tr[now]=max(tr[now<<1|1],tr[now<<1]);
}
int find(int l,int r,int now,int lq,int rq)
{
if(lq<=l&&r<=rq)return tr[now];
int mid=(l+r)>>1,ret=0;
if(mid>=lq)ret=max(ret,find(ls,lq,rq));
if(mid<rq) ret=max(ret,find(rs,lq,rq));
return ret;
}
}A2,B2;
int main()
{
//freopen("tt.in","r",stdin);
scanf("%d%d%*d",&A,&B);
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d%d%d%d%d",&b1[i],&e1[i],&b2[i],&e2[i],&v[i]);
A1.ins(b1[i]);A1.ins(e1[i]);B1.ins(b2[i]);B1.ins(e2[i]);
}
A1.ins(1);B1.ins(1);A1.ins(A);B1.ins(B);
A1.cal();B1.cal();
for(int i=1;i<=n;i++)
A1.trs(b1[i]),A1.trs(e1[i]),B1.trs(b2[i]),B1.trs(e2[i]);
for(int i=1;i<=n;i++)
{
if(e1[i]>b1[i])A1.insert(1,A1.cnt,1,b1[i],e1[i]-1,v[i]);
if(e2[i]>b2[i])B1.insert(1,B1.cnt,1,b2[i],e2[i]-1,v[i]);
}
A1.down(1,A1.cnt,1);B1.down(1,B1.cnt,1);
A2.init(1,A1.cnt,1);B2.init(1,B1.cnt,1);
for(int i=1;i<=n;i++)
{
A2.insert(1,A1.cnt,1,b1[i],e1[i],i);
B2.insert(1,B1.cnt,1,b2[i],e2[i],i);
}
A2.get(1,A1.cnt,1,1);
while(!que.empty())
{
int t=que.top().second,x;que.pop();
if(x=A2.find(1,A1.cnt,1,b1[t],e1[t]))
{
ans+=v[t];
A2.get(1,A1.cnt,1,x);
que.push(PA(v[t],t));
continue;
}
if(x=B2.find(1,B1.cnt,1,b2[t],e2[t]))
{
ans+=v[t];
B2.get(1,B1.cnt,1,x);
que.push(PA(v[t],t));
continue;
}
}
if(A2.tr[1]||B2.tr[1])
{puts("-1");exit(0);}
printf("%lld\n",ans);
return 0;
}
P.S. 救救我,为什么高亮这么迷?