【CSA72G】【XSY3316】rectangle 線段樹 最小生成樹

題目大意

  有一個 \(n\times n\) 的矩陣 \(A\)。最開始 \(A\) 中每一個元素的值都爲 \(0\)算法

  有 \(m\) 次操做,每次給你 \(x_1,x_2,y_1,y_2,w\),對於知足 \(x_1\leq i\leq x_2,y_1\leq j\leq y_2\) 的數對 \((i,j)\),把 \(A_{i,j}\) 的值增長 \(w\)dom

  最後構造一個 \(n\) 個點的無向圖 \(G\)。對於知足 \(1\leq i<j\leq n\) 的數對 \((i,j)\),在 \(G\) 中加一條鏈接着 \(i,j\),邊權爲 \(A_{i,j}\) 的邊。ui

  求 \(G\) 的最小生成樹的邊權和。spa

  \(1\leq n,m\leq 100000,1\leq x_1\leq x_2<y_1\leq y_2\leq n,-{10}^6\leq w\leq {10}^6\)code

題解

  彷佛 prim 和 kruskal 算法都不太好作這道題。get

  還有個算法叫 boruvka。string

  大概就是每一輪對於每一個連通塊求出這個連通塊與其餘連通塊間邊權最小的邊,而後把這兩個連通塊縮在一塊兒。it

  總共會縮 \(O(\log n)\) 輪。io

  用掃描線+線段樹處理出最小值和(連通塊與最小值不一樣)的最小值。function

  這樣若是最小值和 \(i\) 在同一個連通塊中,就選第二個就行了。

  時間複雜度:\(O(m\log^2n)\)

代碼

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<ctime>
#include<functional>
#include<cmath>
#include<vector>
#include<assert.h>
//using namespace std;
using std::min;
using std::max;
using std::swap;
using std::sort;
using std::reverse;
using std::random_shuffle;
using std::lower_bound;
using std::upper_bound;
using std::unique;
using std::vector;
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
typedef std::pair<int,int> pii;
typedef std::pair<ll,ll> pll;
void open(const char *s){
#ifndef ONLINE_JUDGE
    char str[100];sprintf(str,"%s.in",s);freopen(str,"r",stdin);sprintf(str,"%s.out",s);freopen(str,"w",stdout);
#endif
}
void open2(const char *s){
#ifdef DEBUG
    char str[100];sprintf(str,"%s.in",s);freopen(str,"r",stdin);sprintf(str,"%s.out",s);freopen(str,"w",stdout);
#endif
}
int rd(){int s=0,c,b=0;while(((c=getchar())<'0'||c>'9')&&c!='-');if(c=='-'){c=getchar();b=1;}do{s=s*10+c-'0';}while((c=getchar())>='0'&&c<='9');return b?-s:s;}
void put(int x){if(!x){putchar('0');return;}static int c[20];int t=0;while(x){c[++t]=x%10;x/=10;}while(t)putchar(c[t--]+'0');}
int upmin(int &a,int b){if(b<a){a=b;return 1;}return 0;}
int upmax(int &a,int b){if(b>a){a=b;return 1;}return 0;}
const ll inf=0x3fffffffffffffffll;
typedef std::pair<pll,pll> orzzjt;
const int N=100010;
orzzjt merge(orzzjt a,orzzjt b)
{
    orzzjt c;
    if(a.first<b.first)
    {
        c=a;
        if(b.first.second!=c.first.second)
            c.second=min(c.second,b.first);
        else
            c.second=min(c.second,b.second);
    }
    else
    {
        c=b;
        if(a.first.second!=c.first.second)
            c.second=min(c.second,a.first);
        else
            c.second=min(c.second,a.second);
    }
    return c;
}
int c[N];
namespace seg
{
    orzzjt s[4*N];
    ll t[4*N];
    #define mid ((L+R)>>1)
    #define lc (p<<1)
    #define rc ((p<<1)|1)
    void mt(int p)
    {
        s[p]=merge(s[lc],s[rc]);
    }
    void build(int p,int L,int R)
    {
        t[p]=0;
        if(L==R)
        {
            s[p].first=pll(0,c[L]);
            s[p].second=pll(inf,0);
            return;
        }
        build(lc,L,mid);
        build(rc,mid+1,R);
        mt(p);
    }
    void add(int p,ll v)
    {
        t[p]+=v;
        s[p].first.first+=v;
        s[p].second.first+=v;
    }
    void push(int p)
    {
        if(t[p])
        {
            add(lc,t[p]);
            add(rc,t[p]);
            t[p]=0;
        }
    }
    void add(int p,int l,int r,ll v,int L,int R)
    {
        if(l<=L&&r>=R)
        {
            add(p,v);
            return;
        }
        push(p);
        if(l<=mid)
            add(lc,l,r,v,L,mid);
        if(r>mid)
            add(rc,l,r,v,mid+1,R);
        mt(p);
    }
    orzzjt query(int p,int l,int r,int L,int R)
    {
        if(l<=L&&r>=R)
            return s[p];
        push(p);
        if(r<=mid)
            return query(lc,l,r,L,mid);
        if(l>mid)
            return query(rc,l,r,mid+1,R);
        return merge(query(lc,l,r,L,mid),query(rc,l,r,mid+1,R));
    }
}
struct info
{
    int x,y1,y2,w;
    info(int a=0,int b=0,int c=0,int d=0):x(a),y1(b),y2(c),w(d){}
};
int cmp(info a,info b)
{
    return a.x<b.x;
}
info a[4*N];
int n,m;
int t;
int cnt;
int f[N];
ll ans;
int find(int x)
{
    return f[x]==x?x:f[x]=find(f[x]);
}
int merge(int x,int y)
{
    if(find(x)==find(y))
        return 0;
    f[find(x)]=find(y);
    return 1;
}
pll h[N];
int e[N];
int main()
{
    open("72G");
    scanf("%d%d",&n,&m);
    int x1,x2,y1,y2,w;
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d%d%d",&x1,&x2,&y1,&y2,&w);
        a[++t]=info(x1,y1,y2,w);
        a[++t]=info(x2+1,y1,y2,-w);
        a[++t]=info(y1,x1,x2,w);
        a[++t]=info(y2+1,x1,x2,-w);
    }
    sort(a+1,a+t+1,cmp);
    cnt=n;
    for(int i=1;i<=n;i++)
    {
        f[i]=i;
        c[i]=i;
        e[i]=i;
    }
    while(cnt>1)
    {
        seg::build(1,1,n);
        int j=1;
        for(int i=1;i<=cnt;i++)
            h[i]=pll(inf,inf);
        for(int i=1;i<=n;i++)
        {
            for(;j<=t&&a[j].x==i;j++)
                seg::add(1,a[j].y1,a[j].y2,a[j].w,1,n);
            orzzjt s;
            if(i==1)
                s=seg::query(1,i+1,n,1,n);
            else if(i==n)
                s=seg::query(1,1,i-1,1,n);
            else
                s=merge(seg::query(1,1,i-1,1,n),seg::query(1,i+1,n,1,n));
            if(s.first.second!=c[i])
                h[c[i]]=min(h[c[i]],s.first);
            else
                h[c[i]]=min(h[c[i]],s.second);
        }
        for(;j<=t;j++)
            seg::add(1,a[j].y1,a[j].y2,a[j].w,1,n);
        for(int i=1;i<=cnt;i++)
            if(merge(e[i],e[h[i].second]))
                ans+=h[i].first;
        cnt=0;
        for(int i=1;i<=n;i++)
            if(find(i)==i)
            {
                c[i]=++cnt;
                e[cnt]=i;
            }
        for(int i=1;i<=n;i++)
            c[i]=c[find(i)];
    }
    printf("%lld\n",ans);
    return 0;
}
相關文章
相關標籤/搜索
本站公眾號
   歡迎關注本站公眾號,獲取更多信息