日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

CodeForces - 160E Buses and People(线段树+三维偏序)

發(fā)布時間:2024/4/11 编程问答 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 CodeForces - 160E Buses and People(线段树+三维偏序) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

題目鏈接:點擊查看

題目大意:(網(wǎng)上復(fù)制一下別人的題意。。懶)

有n輛公交車,每輛公交車有s(起始點),f(終點),t(發(fā)車時間) (行駛不需要時間)

有m個人,每個人有l(wèi)(起點),r(終點),t(出現(xiàn)時間)

每個人出現(xiàn)后會選擇最早經(jīng)過他且可行的公交車

(即滿足s<=l,r<=f,且公交車發(fā)車時間晚于人出現(xiàn)時間)

輸出每個人會選擇那一輛公交車

如果沒有符合條件的公交車輸出-1

題目分析:這個題目一看到題目中的“sj?≤?li,?ri?≤?fj?and?bi?≤?tj”,感覺就是偏序問題,只不過變成了三維,之前做過最簡單的一維是sort排個序就行,二維的一般是給定兩個區(qū)間[l,r],然后統(tǒng)一對某個端點排序,然后對另一個端點用線段樹就能解決,現(xiàn)在上升到了三維,在給出區(qū)間[l,r]的基礎(chǔ)上,還增加了一個時間t的約束,那么我們應(yīng)該先對其中的一個區(qū)間端點排序,我選擇了對左區(qū)間排序,然后還剩下了右區(qū)間和時間t,題目中說了t都互不相等,我們可以直接對t建線段樹,讓t當(dāng)做下標(biāo),那么維護的權(quán)值肯定和右區(qū)間端點r有關(guān)系,那么我們需要維護什么呢?通過分析之后我們發(fā)現(xiàn),如果我們已經(jīng)建樹后,要找滿足條件(即在區(qū)間[l,r]內(nèi)t最小)的t,我們在查詢的時候會從根節(jié)點出發(fā),一步一步盡量向左區(qū)間移動,因為在線段樹中以t為下標(biāo)建樹,并且t互不相等,那么可以保證左邊的t必定小于右邊的t,那么盡量向左區(qū)間下移的結(jié)果就是所求答案了,我們接下來需要考慮如何在向下移動的時候,一定滿足在區(qū)間[l,r]中呢,首先我們對于左區(qū)間端點l升序處理過了,可以保證當(dāng)遍歷到任意一個查詢的時候,這個查詢左區(qū)間端點之前的公交車已經(jīng)被加入到線段樹中了(即左區(qū)間端點l的條件已經(jīng)滿足),讓t滿足條件并且取最小可以在查詢的時候邊判斷邊下傳,可以保證下傳的時候都是在滿足t的范圍內(nèi)(即公交車的t要小于人的t)下傳的,這樣我們就可以想到,能不能在線段樹中維護右區(qū)間端點的最大值來讓每次下傳都滿足條件呢,每次只要下傳的時候判斷一下右區(qū)間是否在維護的最大值的范圍內(nèi)即可輕易滿足右區(qū)間的條件,因為在某一個時間t的時候,公交車可以開到最大的右端點,那么只要讓所求的右端點小于這個最大值,就能取到這個時間t,從而同時滿足了l和t的約束,這樣一來因為每個時間t都是互不相同的,所以可以通過線段樹來解決這個三維偏序問題。

同樣需要注意一下,t的范圍過大,需要離散化一下,這里不多贅述了,上代碼吧

#include<iostream> #include<cstdio> #include<string> #include<cstring> #include<algorithm> #include<stack> #include<queue> #include<map> #include<cmath> #include<set> #include<sstream> using namespace std;typedef long long LL;const int inf=0x3f3f3f3f;const int N=1e6+100;vector<int>v;int ans[N];struct qu {int l,r,t,id;bool operator<(qu a)const{return l<a.l; } }qu1[N],qu2[N];//qu1儲存的是公交車信息,qu2儲存的是人的信息struct Node {int l,r,mmax,id; }tree[N<<2];void pushup(int k) {tree[k].mmax=max(tree[k<<1].mmax,tree[k<<1|1].mmax); }void build(int k,int l,int r) {tree[k].l=l;tree[k].r=r;tree[k].mmax=0;tree[k].id=-1;if(l==r)return;int mid=l+r>>1;build(k<<1,l,mid);build(k<<1|1,mid+1,r); }void update(int k,int pos,int val,int id) {if(tree[k].l==tree[k].r){tree[k].mmax=val;tree[k].id=id;return;}int mid=tree[k].l+tree[k].r>>1;if(mid>=pos)update(k<<1,pos,val,id);elseupdate(k<<1|1,pos,val,id);pushup(k); }int query(int k,int num,int b) {if(tree[k].mmax<num)return -1;if(tree[k].l==tree[k].r)return tree[k].id;int mid=tree[k].l+tree[k].r>>1;int ans=-1;if(mid>=b){ans=query(k<<1,num,b);if(ans>0)return ans;}return query(k<<1|1,num,b); }int getid(int num)//離散化:獲得新編號 {return lower_bound(v.begin(),v.end(),num)-v.begin()+1; }int main() { // freopen("input.txt","r",stdin);int n,m;while(scanf("%d%d",&n,&m)!=EOF){v.clear();for(int i=1;i<=n;i++){scanf("%d%d%d",&qu1[i].l,&qu1[i].r,&qu1[i].t);v.push_back(qu1[i].t);qu1[i].id=i;}for(int i=1;i<=m;i++){scanf("%d%d%d",&qu2[i].l,&qu2[i].r,&qu2[i].t);qu2[i].id=i;v.push_back(qu2[i].t);}sort(v.begin(),v.end());//離散化:排序v.erase(unique(v.begin(),v.end()),v.end());//離散化:去重sort(qu1+1,qu1+1+n);//對公交車的左區(qū)間端點排序sort(qu2+1,qu2+1+m);//對人的左區(qū)間端點排序int cnt=1;build(1,1,v.size());//建樹,這里一定要記著,線段樹是要用離散化后t的個數(shù)來建樹,一開始習(xí)慣性的用n建樹,結(jié)果連樣例都過不去。。自閉for(int i=1;i<=m;i++){/* if(qu1[cnt].l>qu2[i].l)//不知道為什么加了這么一段剪枝會WA。。(可能是我太菜了){ans[qu2[i].id]=-1;continue;}*/while(qu1[cnt].l<=qu2[i].l&&cnt<=n)//每次先把左區(qū)間人左邊的公交車全部加入線段樹中{update(1,getid(qu1[cnt].t),qu1[cnt].r,qu1[cnt].id);cnt++;}ans[qu2[i].id]=query(1,qu2[i].r,getid(qu2[i].t));}for(int i=1;i<=m;i++)printf("%d ",ans[i]);cout<<endl;}return 0; }

?

總結(jié)

以上是生活随笔為你收集整理的CodeForces - 160E Buses and People(线段树+三维偏序)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。