1. 程式人生 > 實用技巧 >2018ICPC首爾A題 Circuits(線段樹)

2018ICPC首爾A題 Circuits(線段樹)

經典套路,首先發現只有兩個邊,這種情況下,很容易想到使用列舉的方法,列舉第一條邊,然後計算對應的第二邊最優,之後對於所有情況取max

這裡只有y有用並且每個矩形其實就是一條線段

對於這題,一個需要考慮的問題是,如何當我們列舉一條邊的時候,計算第二邊答案的時候不會計算進第一條已經穿過的矩形。

那麼其實這也是另一個套路,只要我們動態加邊,倒著列舉,列舉每個點時,線段樹中只有後面不會被當前點穿過的邊,然後再維護一個字首和,表示每個點能穿過的邊

兩個答案相加就是當前列舉點的答案

#include<bits/stdc++.h>
using namespace std;
typedef long
long ll; typedef pair<int,int> pll; const int N=2e5+10; vector<int> num; vector<int> g[N]; int l[N],r[N]; int sum[N]; struct node{ int l,r; int mx; int lazy; }tr[N<<2]; int find(int x){ return lower_bound(num.begin(),num.end(),x)-num.begin()+1; } void build(int
u,int l,int r){ if(l==r){ tr[u]={l,r}; } else{ tr[u]={l,r}; int mid=l+r>>1; build(u<<1,l,mid); build(u<<1|1,mid+1,r); } } void pushdown(int u){ int x=tr[u].lazy; tr[u<<1].mx+=x; tr[u<<1|1].mx+=x; tr[u
<<1].lazy+=x; tr[u<<1|1].lazy+=x; tr[u].lazy=0; } void pushup(int u){ tr[u].mx=max(tr[u<<1].mx,tr[u<<1|1].mx); } void modify(int u,int l,int r,int x){ if(tr[u].l>=l&&tr[u].r<=r){ tr[u].mx+=x; tr[u].lazy+=x; return ; } if(tr[u].lazy) pushdown(u); int mid=tr[u].l+tr[u].r>>1; if(l<=mid) modify(u<<1,l,r,x); if(r>mid) modify(u<<1|1,l,r,x); pushup(u); } int main(){ int n; ios::sync_with_stdio(false); cin>>n; int i; for(i=1;i<=n;i++){ int a,b,c,d; cin>>a>>b>>c>>d; l[i]=d,r[i]=b; num.push_back(b); num.push_back(d); } sort(num.begin(),num.end()); num.erase(unique(num.begin(),num.end()),num.end()); for(i=1;i<=n;i++){ l[i]=find(l[i]); r[i]=find(r[i]); g[l[i]].push_back(r[i]); sum[l[i]]++,sum[r[i]+1]--; } for(i=1;i<=(int)num.size();i++){ sum[i]+=sum[i-1]; } int ans=0; build(1,1,(int)num.size()); for(i=(int)num.size();i>=1;i--){ ans=max(ans,sum[i]+tr[1].mx); for(auto x:g[i]){ modify(1,i,x,1); } } cout<<ans<<endl; }
View Code