HDU 5517 三维偏序 二维树状数组

爱被打了一巴掌 2022-05-08 08:28 345阅读 0赞

题意:已知A集合(a,b),B集合(c,d,e)C=A*B=(a, c, d)在b和e相等的情况下才可以,问题是求出C中有几个元素,该元素除了自己没有比他大的,’>’的定义是当 a>=a’ && b>=b’ && c>=c’时,才成立。

思路:三位偏序cdq可以解决,但是如果抓住c,d的范围是1000的话,可以直接用二维树状数组代替。

由于A集合大小是1e5,B集合大小也是1e5,直接运算c集合能爆,对于A集合,同一个b只要取a最大的保留就可以,

这样出题人给出最大数据C集合只能到1e5的大小。

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. const int N=1e5+10;
  4. struct PAIR{
  5. int a, b;
  6. bool operator <(PAIR t) const{
  7. return b<t.b || b==t.b && a>t.a;
  8. }
  9. }p[N];
  10. struct Triple{
  11. int a, b, c, cnt;
  12. bool operator < (Triple t) const{
  13. return c<t.c;
  14. }
  15. }tr[N], C[N];
  16. int n, m, num[N];
  17. bool cmp(Triple a, Triple b){
  18. return a.a>b.a||a.a==b.a&&a.b>b.b||a.a==b.a&&a.b==b.b&&a.c>b.c;
  19. }
  20. int s[1010][1010];
  21. void upd(int a, int b, int v){
  22. for(int x=a;x>0;x-=x&-x)
  23. for(int y=b; y>0; y-=y&-y)
  24. s[x][y]+=v;
  25. }
  26. int query(int a, int b){
  27. int ret=0;
  28. for(int x=a;x<1010;x+=x&-x)
  29. for(int y=b;y<1010;y+=y&-y)
  30. ret+=s[x][y];
  31. return ret;
  32. }
  33. void ss(struct PAIR q[], int nn){
  34. for(int i=1; i<=nn; i++)
  35. printf("(%d, %d) ", q[i].a, q[i].b);
  36. puts("");
  37. }
  38. void show(struct Triple q[], int nn){
  39. for(int i=1; i<=nn; i++)
  40. printf("(%d, %d, %d) ", q[i].a, q[i].b, q[i].c);
  41. puts("");
  42. }
  43. int main(){
  44. /*upd(2, 4, 3);
  45. printf("%d\n", query(1, 4));*/
  46. int T, cas=0;
  47. scanf("%d", &T);
  48. while(T--){
  49. memset(num, 0, sizeof num);
  50. memset(s, 0, sizeof s);
  51. scanf("%d%d", &n, &m);
  52. for(int i=1; i<=n; i++)
  53. scanf("%d%d", &p[i].a, &p[i].b);
  54. for(int i=1; i<=m; i++)
  55. scanf("%d%d%d", &tr[i].a, &tr[i].b, &tr[i].c);
  56. sort(p+1, p+1+n);
  57. int tot=0, a=-1, b=-1, c=-1;
  58. for(int i=1; i<=n; i++){
  59. if(p[i].b==b){
  60. if(p[i].a==a)
  61. num[tot]++;
  62. //cout<<"***"<<endl;
  63. }
  64. else{
  65. b=p[++tot].b=p[i].b;
  66. a=p[tot].a=p[i].a;
  67. num[tot]=1;
  68. }
  69. }
  70. int n1=0;
  71. for(int i=1; i<=tot; i++){
  72. for(int j=1; j<=m; j++){
  73. if(p[i].b==tr[j].c){
  74. C[++n1].a=p[i].a;
  75. C[n1].b=tr[j].a;
  76. C[n1].c=tr[j].b;
  77. C[n1].cnt=num[i];
  78. }
  79. }
  80. }
  81. // ss(p, tot);
  82. /*show(tr, m);
  83. show(C, n1);*/
  84. sort(C+1, C+1+n1, cmp);
  85. a=-1, b=-1, c=-1;
  86. int n2=0;
  87. for(int i=1; i<=n1; i++){
  88. if(C[i].a==a && C[i].b==b && C[i].c==c)
  89. C[n2].cnt+=C[i].cnt;
  90. else{
  91. C[++n2]=C[i];
  92. a=C[i].a; b=C[i].b; c=C[i].c;
  93. }
  94. }
  95. int ans=0;
  96. for(int i=1; i<=n2; i++){
  97. if(query(C[i].b, C[i].c)==0){
  98. ans+=C[i].cnt;
  99. // printf("(%d, %d, %d): %d\n", C[i].a, C[i].b, C[i].c, C[i].cnt);
  100. }
  101. upd(C[i].b, C[i].c, 1);
  102. }
  103. printf("Case #%d: %d\n", ++cas, ans);
  104. }
  105. return 0;
  106. }

发表评论

表情:
评论列表 (有 0 条评论,345人围观)

还没有评论,来说两句吧...

相关阅读

    相关 树状数组 hdu2689 hdu2838

    题意:给定一个正整数n,和一个1-n的一个排列,每个数可以和旁边的两个数的任意一个交换,每交换一次总次数就要加一,问将这个排列转换成一个递增的排列需要多少次交换? 题意可以转