傳送門(mén)
文章目錄
題意:
給你nnn個(gè)點(diǎn)(xi,yi)(x_i,y_i)(xi?,yi?),每個(gè)點(diǎn)有個(gè)價(jià)值cic_ici?,現(xiàn)在你可以框一個(gè)正方形,要求左下角和右上角的坐標(biāo)(x,y)(x,y)(x,y)必須x=yx=yx=y,也就是說(shuō)必須在x=yx=yx=y這條直線上。現(xiàn)在你可以框一個(gè)正方形,被正方形框到的點(diǎn)算入總價(jià)值,求能得到的最大的總價(jià)值。總價(jià)值=被框的點(diǎn)的價(jià)值?-?正方形的長(zhǎng)度。
思路:
在二維平面畫(huà)了很多都沒(méi)找到規(guī)律,看了題解才知道,這個(gè)題有一個(gè)很巧妙的轉(zhuǎn)換,設(shè)正方形左下角坐標(biāo)(x,x)(x,x)(x,x),右上角坐標(biāo)(y,y)(y,y)(y,y),對(duì)于(xi,yi)(x_i,y_i)(xi?,yi?)如果他能被這個(gè)正方形包含在內(nèi)部,那么必須滿足x<=min(xi,yi)<=max(xi,yi)<=yx<=min(x_i,y_i)<=max(x_i,y_i)<=yx<=min(xi?,yi?)<=max(xi?,yi?)<=y。看到這個(gè)式子,很明顯它可以將每個(gè)點(diǎn)轉(zhuǎn)換成一個(gè)區(qū)間的形式,即[min(xi,yi),max(xi,yi)][min(x_i,y_i),max(x_i,y_i)][min(xi?,yi?),max(xi?,yi?)]。
現(xiàn)在我們重新描述以下這個(gè)問(wèn)題,給你若干個(gè)區(qū)間,每個(gè)區(qū)間有一個(gè)價(jià)值,你需要覆蓋一段區(qū)間,使得覆蓋到的區(qū)間的價(jià)值?-?區(qū)間長(zhǎng)度最大。當(dāng)然這里覆蓋是必須完全覆蓋。
轉(zhuǎn)換成這個(gè)問(wèn)題,就比較容易做了,這里介紹一種線段樹(shù)的做法。
首先需要發(fā)現(xiàn)一個(gè)性質(zhì),那就是我們選的區(qū)間起點(diǎn)一定是某個(gè)區(qū)間的起點(diǎn),終點(diǎn)一定是某個(gè)區(qū)間的終點(diǎn)。這個(gè)比較顯然。
那么我們將左端點(diǎn)按從小到大排序,讓后倒著掃,每次都將當(dāng)前左端點(diǎn)相等的區(qū)間都加入,即將[yi,1e9][y_i,1e9][yi?,1e9]都加上cic_ici?。這樣可保證以左端點(diǎn)為起點(diǎn)能求解出最佳答案。
以上操作顯然可仍線段樹(shù)里面,現(xiàn)在我們問(wèn)題就轉(zhuǎn)換成了如何求出來(lái)tree(xi,1e9)max?(r?xi)tree(x_i,1e9)_{max}-(r-x_i)tree(xi?,1e9)max??(r?xi?),前面一部分就是線段樹(shù)區(qū)間最大值的查詢(xún),對(duì)于后面,由于我們枚舉的xix_ixi?,所以xix_ixi?已經(jīng)知道了,我們可將其移動(dòng)一下變成xi+tree(xi,1e9)max?rx_i+tree(x_i,1e9)_{max}-rxi?+tree(xi?,1e9)max??r,那么rrr怎么辦呢?我們可以在建線段樹(shù)的時(shí)候?qū)⒊跏贾抵脼槠?span id="ozvdkddzhkzd" class="katex--inline">rrr即可,查詢(xún)的時(shí)候需要加上左端點(diǎn)。
讓后可以離散化一下比較好些,當(dāng)然也可以動(dòng)態(tài)開(kāi)點(diǎn)?
復(fù)雜度O(nlogn)O(nlogn)O(nlogn)
#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
#include<map>
#include<cmath>
#include<cctype>
#include<vector>
#include<set>
#include<queue>
#include<algorithm>
#include<sstream>
#include<ctime>
#include<cstdlib>
#include<random>
#include<cassert>
#define X first
#define Y second
#define L (u<<1)
#define R (u<<1|1)
#define pb push_back
#define mk make_pair
#define Mid ((tr[u].l+tr[u].r)>>1)
#define Len(u) (tr[u].r-tr[u].l+1)
#define random(a,b) ((a)+rand()%((b)-(a)+1))
#define db puts("---")
using namespace std
;
typedef long long LL
;
typedef unsigned long long ULL
;
typedef pair
<int,int> PII
;const int N
=1000010,mod
=1e9+7,INF
=0x3f3f3f3f;
const LL inf
=0x3f3f3f3f3f3f3f3f;
const double eps
=1e-6;int n
,se
;
struct node {int X
,Y
,c
;bool operator < (const node
&x
) const {return x
.X
>X
;}
}p
[N
];
vector
<int>v
;
struct Node {int l
,r
;LL now
,mx
,lazy
,id
;
}tr
[N
<<2];int find(int x
) {return lower_bound(v
.begin(),v
.end(),x
)-v
.begin()+1;
}void pushup(int u
) {if(tr
[L
].mx
>tr
[R
].mx
) {tr
[u
].mx
=tr
[L
].mx
;tr
[u
].id
=tr
[L
].id
;} else {tr
[u
].mx
=tr
[R
].mx
;tr
[u
].id
=tr
[R
].id
;}
}void pushdown(int u
) {LL lazy
=tr
[u
].lazy
; tr
[u
].lazy
=0;tr
[L
].lazy
+=lazy
; tr
[L
].mx
+=lazy
;tr
[R
].lazy
+=lazy
; tr
[R
].mx
+=lazy
;
}void build(int u
,int l
,int r
) {tr
[u
]={l
,r
,0,0,0,0};if(l
==r
) {tr
[u
].mx
=-v
[l
-1];tr
[u
].id
=v
[l
-1];return ;}build(L
,l
,Mid
); build(R
,Mid
+1,r
);pushup(u
);
}void change(int u
,int l
,int r
,int c
) {if(tr
[u
].l
>=l
&&tr
[u
].r
<=r
) {tr
[u
].mx
+=c
; tr
[u
].lazy
+=c
;return;}pushdown(u
);if(l
<=Mid
) change(L
,l
,r
,c
);if(r
>Mid
) change(R
,l
,r
,c
);pushup(u
);
}pair
<LL
,int> query(int u
,int l
,int r
) {if(tr
[u
].l
>=l
&&tr
[u
].r
<=r
) return {tr
[u
].mx
,tr
[u
].id
};pushdown(u
);pair
<LL
,int> ans
={-inf
,0};if(l
<=Mid
) ans
=max(ans
,query(L
,l
,r
));if(r
>Mid
) ans
=max(ans
,query(R
,l
,r
));return ans
;
}int main()
{
LL ans
=0;int l
=mod
,r
=mod
;scanf("%d",&n
);for(int i
=1;i
<=n
;i
++) {scanf("%d%d%d",&p
[i
].X
,&p
[i
].Y
,&p
[i
].c
);if(p
[i
].X
>p
[i
].Y
) swap(p
[i
].X
,p
[i
].Y
);v
.pb(p
[i
].X
); v
.pb(p
[i
].Y
);}sort(v
.begin(),v
.end()); v
.erase(unique(v
.begin(),v
.end()),v
.end());sort(p
+1,p
+1+n
); se
=v
.size();for(int i
=1;i
<=n
;i
++) p
[i
].X
=find(p
[i
].X
),p
[i
].Y
=find(p
[i
].Y
);build(1,1,se
);for(int i
=n
;i
>=1;i
--) {int xx
=p
[i
].X
;while(i
>=1&&p
[i
].X
==xx
) change(1,p
[i
].Y
,se
,p
[i
].c
),i
--; i
++;pair
<LL
,int> now
=query(1,p
[i
].X
,se
);now
.X
+=v
[p
[i
].X
-1];if(now
.X
>ans
) {ans
=now
.X
;l
=v
[p
[i
].X
-1],r
=now
.Y
;}}printf("%lld\n%d %d %d %d\n",ans
,l
,l
,r
,r
);return 0;
}
總結(jié)
以上是生活随笔為你收集整理的Educational Codeforces Round 73 (Rated for Div. 2) F. Choose a Square 线段树 + 二维转一维的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。