你说得对,谁是奶龙呢?
你聪明的,告诉我,你到底改了什么呢?(Boruvka 不是原题最直观但过不去的做法吗)
思路浅析:
看到近乎完全图的生成树问题,立马想到 Boruvka。
边权的绝对值考虑拆开,对
查询与我的边权最小的点即是与我有交的中
标记永久化的做法,感觉很聪明啊(不对啊,这玩意是不是就是线段树区间加查的方法,总之就是十分聪明!)!
考虑线段树的结构,区间询问和修改都被搞到了
被包含的修改考虑在所有经过经过的节点单独记录它的贡献,查询时调用询问拆出来的节点记录的被包含贡献即可,包含的修改就直接在被修改的节点记录,查询时查所有经过区间即可。
Boruvka 注意到要维护一个不同颜色次小来找不同色最小点。
时间复杂度
参考代码:
#include<bits/stdc++.h>
#define ll int
#define INF 1147483647
using namespace std;
ll t,n;
ll f[100005];
ll find(ll x)
{
return x==f[x]?x:f[x]=find(f[x]);
}
struct px
{
ll l,r,a,b;
bool operator<(const px&bb)const
{
return b<bb.b;
}
}s[100005];
struct xp
{
ll val,col;
bool operator<(const xp&b)const
{
return val<b.val;
}
xp(ll a=INF,ll b=0)
{
val=a;col=b;
}
}minn[100005];
struct nv
{
xp minn,smin;
};
struct tree
{
nv mt,up;
}tr[800005];
#define ls(id) id*2
#define rs(id) id*2+1
nv merge(nv a,xp s)
{
if(a.minn.col==s.col)a.minn=min(a.minn,s);
else if(s<a.minn)swap(a.minn,a.smin),a.minn=s;
else a.smin=min(a.smin,s);
return a;
}
nv mg(nv a,nv b)
{
a=merge(a,b.minn);
a=merge(a,b.smin);
return a;
}
void update(ll id,ll l,ll r,ll ml,ll mr,xp s)
{
tr[id].up=merge(tr[id].up,s);
if(ml<=l&&r<=mr)
{
tr[id].mt=merge(tr[id].mt,s);
return;
}
ll mid=l+r>>1;
if(ml<=mid)update(ls(id),l,mid,ml,mr,s);
if(mr>mid)update(rs(id),1+mid,r,ml,mr,s);
}
nv query(ll id,ll l,ll r,ll ml,ll mr)
{
if(ml<=l&&r<=mr)return tr[id].up;
ll mid=l+r>>1;
nv res=tr[id].mt;
if(ml<=mid)res=mg(res,query(ls(id),l,mid,ml,mr));
if(mr>mid)res=mg(res,query(rs(id),1+mid,r,ml,mr));
return res;
}
ll p[200005],tot;
int main()
{
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin>>t;
while(t--)
{
cin>>n;
tot=0;
for(ll i=1;i<=n;++i)f[i]=i,cin>>s[i].l>>s[i].r>>s[i].a>>s[i].b,p[++tot]=s[i].l,p[++tot]=s[i].r;
sort(s+1,s+1+n);
sort(p+1,p+1+tot);
tot=unique(p+1,p+1+tot)-p-1;
for(ll i=1;i<=n;++i)
{
s[i].l=lower_bound(p+1,p+1+tot,s[i].l)-p;
s[i].r=lower_bound(p+1,p+1+tot,s[i].r)-p;
}
long long res=0;
ll cot=0;
while(1)
{
ll lc=cot;
for(ll i=1;i<=4*tot;++i)tr[i].mt.minn=tr[i].mt.smin=tr[i].up.minn=tr[i].up.smin=xp();
unordered_set<ll>d;
for(ll i=1;i<=n;++i)minn[i]=xp(),d.insert(find(i));
for(ll i=1;i<=n;++i)
{
nv res=query(1,1,tot,s[i].l,s[i].r);
res.minn.val+=s[i].a+s[i].b;
res.smin.val+=s[i].a+s[i].b;
if(res.minn.col==find(i))minn[find(i)]=min(minn[find(i)],res.smin);
else minn[find(i)]=min(minn[find(i)],res.minn);
update(1,1,tot,s[i].l,s[i].r,xp(s[i].a-s[i].b,find(i)));
}
for(ll i=1;i<=4*tot;++i)tr[i].mt.minn=tr[i].mt.smin=tr[i].up.minn=tr[i].up.smin=xp();
for(ll i=n;i;--i)
{
nv res=query(1,1,tot,s[i].l,s[i].r);
res.minn.val+=s[i].a-s[i].b;
res.smin.val+=s[i].a-s[i].b;
if(res.minn.col==find(i))minn[find(i)]=min(minn[find(i)],res.smin);
else minn[find(i)]=min(minn[find(i)],res.minn);
update(1,1,tot,s[i].l,s[i].r,xp(s[i].a+s[i].b,find(i)));
}
for(auto it:d)
{
if(minn[it].col==0)continue;
ll u=find(it),v=find(minn[it].col);
if(u!=v)
{
++cot;res+=minn[it].val;
f[u]=v;
}
}
if(cot==lc)break;
}
if(cot!=n-1)cout<<-1<<'\n';
else cout<<res<<'\n';
}
}