習題: Developing Game(掃描線&線段樹)
阿新 • • 發佈:2020-08-24
題目
思路
我們考慮怎麼將轉換這個限制
考慮最終的答案一定滿足一個式子,對於方案中的任意一個人都滿足\(l_i<=min\{v_i\}<=v_i<=max\{v_i\}<=r_i\)
我們把平面內的每一個點看做\((min\{v_i\},max\{v_i\})\)
把其轉換成為一個矩陣,矩陣的左下角的左邊即為\((l_i,v_i)\),右上角的座標即為\((v_i,r_i)\),
之後就是求最多有多少個矩陣重疊在一起,這就是一個掃描線的板子了
程式碼
#include<iostream> #include<vector> using namespace std; namespace lst { struct node { int l,r; int maxx,lazy,_ind; }tre[1200005]; void build(int l,int r,int k) { tre[k].l=l; tre[k].r=r; if(l==r) { tre[k]._ind=l; return; } int mid=(l+r)>>1; build(l,mid,k<<1); build(mid+1,r,k<<1|1); tre[k].maxx=max(tre[k<<1].maxx,tre[k<<1|1].maxx); tre[k]._ind=(tre[k].maxx==tre[k<<1].maxx?tre[k<<1]._ind:tre[k<<1|1]._ind); } void push_down(int k) { tre[k<<1].lazy+=tre[k].lazy; tre[k<<1].maxx+=tre[k].lazy; tre[k<<1|1].lazy+=tre[k].lazy; tre[k<<1|1].maxx+=tre[k].lazy; tre[k].lazy=0; } void change(int l,int r,int val,int k=1) { if(l>tre[k].r||tre[k].l>r) return; if(l<=tre[k].l&&tre[k].r<=r) { tre[k].maxx+=val; tre[k].lazy+=val; return; } push_down(k); change(l,r,val,k<<1); change(l,r,val,k<<1|1); tre[k].maxx=max(tre[k<<1].maxx,tre[k<<1|1].maxx); tre[k]._ind=(tre[k].maxx==tre[k<<1].maxx?tre[k<<1]._ind:tre[k<<1|1]._ind); } } using namespace lst; struct NODE { int l,v,r; }a[100005]; struct ls { int l,r; }; int n; int maxx,limit,ans; pair<int,int> li; vector<ls> ad[300005]; vector<ls> de[300005]; int main() { cin>>n; for(int i=1;i<=n;i++) { cin>>a[i].l>>a[i].v>>a[i].r; maxx=max(a[i].v,maxx); limit=max(a[i].r,limit); ad[a[i].l].push_back((ls){a[i].v,a[i].r}); de[a[i].v].push_back((ls){a[i].v,a[i].r}); } build(1,limit,1); for(int i=1;i<=maxx;i++) { for(int j=0;j<ad[i].size();j++) change(ad[i][j].l,ad[i][j].r,1); for(int j=0;j<de[i-1].size();j++) change(de[i-1][j].l,de[i-1][j].r,-1); if(tre[1].maxx>ans) { ans=tre[1].maxx; li=make_pair(i,tre[1]._ind); } } int f=1; cout<<ans<<'\n'; for(int i=1;i<=n;i++) { if(a[i].l<=li.first&&li.first<=a[i].v&&a[i].v<=li.second&&li.second<=a[i].r) { if(f) { cout<<i; f=0; } else cout<<' '<<i; } } return 0; }