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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

HDU - 5517 Triple(三维偏序-二维树状数组/CDQ分治)

發布時間:2024/4/11 编程问答 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 HDU - 5517 Triple(三维偏序-二维树状数组/CDQ分治) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

題目鏈接:點擊查看

題目大意:給出 n 個二元對 ( a , b ) 和 m 個三元對 ( c , d , e ),對于所有 b == e 的二元對和三元對,可以通過某種運算形成一個新的三元對 ( a , c , d ) ,現在問所有的 ( a , c , d ) 中,有多少個三元對滿足,不存在另一個三元對 ( a1 , c1 , d1 ) 滿足 a1 >= a && c1 >= c && d1 >= d

題目分析:首先需要分析出來,對于所有的二元對 ( a , b ) 來說,對于每個 b ,我們只需要映射一下其最大的 a 即可,因為假設存在兩個二元對 ( a1 , b ) 和 ( a2 , b ) 滿足 a1 > a2,其能組成的所有三元對中,( a1 , c , d ) 和 ( a2 , c , d ) 一定滿足 a1 >= a2 && c >= c && d >= d,故 a2 一定沒有貢獻,知道了這一點后,又因為 m 最大才為 1e5,所以最后可以做出貢獻的三元對最多也只有 1e5 個,我們只需要對這些三元對進行討論即可

將這些新的三元對儲存起來后, 剩下的就是一個簡單的三維偏序問題了,又因為 c 和 d 的范圍都非常小,所以可以用二維樹狀數組來解決,時間復雜度為 nlog^2n,也可以用樸素的 CDQ分治 解決,時間復雜度同為 nlog^2n,不過顯然前者的常數要小很多,表現的更加優秀

稍微講一下二者該如何解決吧,二維樹狀數組應該比較好理解,說是樹套樹,其實就是在原有的一維數組和循環的基礎上,多套了一層循環罷了,維護的是 ( 0 , 0 ) ~ ( x , y?) 這個二維矩陣中點的個數,這樣一來就可以將三維偏序中的第二維和第三維抽象成二維矩陣上的點表示,在第一維降序排序的基礎上,對于某個點 ( x , y ) ,如果 ( x , y ) ~ ( 1000 , 1000 ) 中存在點的話,那就說明肯定存在這一個三元組的每一項都分別大于當前的這一項,故不符合條件,反之符合條件

然后就是CDQ分治,這個沒什么好說的了,按照第一維降序排序,第二維放在歸并排序中仍然降序,第三維用樹狀數組維護,分別記錄每個位置的貢獻即可

最后就是特判一下無解的情況,以及對于所有相同位置的點,需要壓縮成一個點,不然會相互影響

代碼:

二維樹狀數組

#include<iostream> #include<cstdio> #include<string> #include<ctime> #include<cmath> #include<cstring> #include<algorithm> #include<stack> #include<climits> #include<queue> #include<map> #include<set> #include<sstream> #include<cassert> #include<bitset> using namespace std;typedef long long LL;typedef unsigned long long ull;const int inf=0x3f3f3f3f;const int N=1e5+100;struct Node {int a,b,c,num;Node(int a,int b,int c,int num):a(a),b(b),c(c),num(num){}bool operator==(const Node& t)const{return a==t.a&&b==t.b&&c==t.c;} };vector<Node>node1,node2;int b[N],num[N],c[1100][1100];int lowbit(int x) {return x&(-x); }int add(int x,int y)//(x,y)的位置加1 {for(int i=x;i<=1000;i+=lowbit(i))for(int j=y;j<=1000;j+=lowbit(j))c[i][j]++; }int ask(int x,int y)//返回(0,0)~(x,y)的矩陣和 {int ans=0;for(int i=x;i>0;i-=lowbit(i))for(int j=y;j>0;j-=lowbit(j))ans+=c[i][j];return ans; }int query(int x,int y)//返回(x,y)~(1000,1000)的矩陣和 {return ask(1000,1000)-ask(x-1,1000)-ask(1000,y-1)+ask(x-1,y-1); }void init() {node1.clear();node2.clear();memset(b,0,sizeof(b));memset(num,0,sizeof(num));memset(c,0,sizeof(c)); }int main() { #ifndef ONLINE_JUDGE // freopen("data.in.txt","r",stdin); // freopen("data.out.txt","w",stdout); #endif // ios::sync_with_stdio(false);int w;cin>>w;int kase=0;while(w--){init();int n,m;scanf("%d%d",&n,&m);for(int i=1;i<=n;i++){int x,y;scanf("%d%d",&x,&y);if(b[y]<x){b[y]=x;num[y]=1;}else if(b[y]==x)num[y]++;}for(int i=1;i<=m;i++){int x,y,z;scanf("%d%d%d",&x,&y,&z);if(b[z])node1.push_back(Node(b[z],x,y,num[z]));}if(node1.empty()){printf("Case #%d: 0\n",++kase);continue;}sort(node1.begin(),node1.end(),[&](Node a,Node b){if(a.a!=b.a)return a.a>b.a;if(a.b!=b.b)return a.b>b.b;return a.c>b.c;});node2.push_back(node1[0]);for(int i=1;i<node1.size();i++){if(node2.back()==node1[i])node2.back().num+=node1[i].num;elsenode2.push_back(node1[i]);}int ans=0;for(int i=0;i<node2.size();i++){if(!query(node2[i].b,node2[i].c))ans+=node2[i].num;add(node2[i].b,node2[i].c);}printf("Case #%d: %d\n",++kase,ans);}return 0; }

CDQ分治

#include<iostream> #include<cstdio> #include<string> #include<ctime> #include<cmath> #include<cstring> #include<algorithm> #include<stack> #include<climits> #include<queue> #include<map> #include<set> #include<sstream> #include<cassert> #include<bitset> #include<unordered_map> using namespace std;typedef long long LL;typedef unsigned long long ull;const int inf=0x3f3f3f3f;const int N=1e5+100;struct Node {int a,b,c,num,id;Node():a(0),b(0),c(0){}Node(int a,int b,int c,int num):a(a),b(b),c(c),num(num){}bool operator==(const Node& t)const{return a==t.a&&b==t.b&&c==t.c;} }t[N];vector<Node>node1,node2;int b[N],num[N],c[1100],vis[N];int lowbit(int x) {return x&(-x); }int add(int x,int val) {for(int i=x;i<=1000;i+=lowbit(i))c[i]+=val; }int ask(int x) {int ans=0;for(int i=x;i>0;i-=lowbit(i))ans+=c[i];return ans; }bool cmp(Node a,Node b) {if(a.b!=b.b)return a.b>b.b;return a.c>b.c; }void CDQ(int l,int r) {if(l==r)return;int mid=l+r>>1;CDQ(l,mid);CDQ(mid+1,r);for(int i=l;i<=r;i++)t[i]=node2[i];sort(t+l,t+mid+1,cmp);sort(t+mid+1,t+r+1,cmp);int p=l,q=mid+1;while(p<=mid&&q<=r){if(t[p].b>=t[q].b){add(t[p].c,1);p++;}else{vis[t[q].id]+=ask(1000)-ask(t[q].c-1);q++;}}while(p<=mid){add(t[p].c,1);p++;}while(q<=r){vis[t[q].id]+=ask(1000)-ask(t[q].c-1);q++;}for(int i=l;i<=mid;i++)add(t[i].c,-1); }void init() {node1.clear();node2.clear();memset(b,0,sizeof(b));memset(num,0,sizeof(num));memset(c,0,sizeof(c));memset(vis,0,sizeof(vis)); }int main() { #ifndef ONLINE_JUDGE // freopen("data.in.txt","r",stdin); // freopen("data.out.txt","w",stdout); #endif // ios::sync_with_stdio(false);int w;cin>>w;int kase=0;while(w--){init();int n,m;scanf("%d%d",&n,&m);for(int i=1;i<=n;i++){int x,y;scanf("%d%d",&x,&y);if(b[y]<x){b[y]=x;num[y]=1;}else if(b[y]==x)num[y]++;}for(int i=1;i<=m;i++){int x,y,z;scanf("%d%d%d",&x,&y,&z);if(b[z])node1.push_back(Node(b[z],x,y,num[z]));}if(node1.empty()){printf("Case #%d: 0\n",++kase);continue;}sort(node1.begin(),node1.end(),[&](Node a,Node b){if(a.a!=b.a)return a.a>b.a;if(a.b!=b.b)return a.b>b.b;return a.c>b.c;});node2.push_back(Node());for(int i=0;i<node1.size();i++){if(node2.back()==node1[i])node2.back().num+=node1[i].num;else{node2.push_back(node1[i]);node2.back().id=node2.size()-1;}}int nn=node2.size()-1;CDQ(1,nn);int ans=0;for(int i=1;i<=nn;i++)if(!vis[node2[i].id])ans+=node2[i].num;printf("Case #%d: %d\n",++kase,ans);}return 0; }

?

總結

以上是生活随笔為你收集整理的HDU - 5517 Triple(三维偏序-二维树状数组/CDQ分治)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。