sdut-2159 Ivan comes again!(set+线段树)

Ivan comes again!

Time
Limit: 1000ms   Memory limit: 65536K  有疑问?点这里^_^

题目描述

The Fairy Ivan gave Saya three problems to solve (Problem F). After Saya finished the first problem (Problem H), here comes the second.

This is the enhanced version of Problem H.

There is a large matrix whose row
and column are less than or equal to 1000000000. And there are three operations for the matrix:

1)add:
Mark an element in the matrix. The element wasn’t marked before it is marked.

2)remove:
Delete an element’s mark. The element was marked before the element’s mark is deleted.

3)find:
Show an element’s row and column, and return a marked element’s row and column, where the marked element’s row and column are larger than the showed element’s row and column respectively. If there are multiple solutions, return the element whose row is the
smallest; and if there are still multiple solutions, return the element whose column is the smallest. If there is no solution, return -1.

Of course, Saya
comes to you for help again.

输入

The input consists of several test cases.

The first line of input in each test case contains one integer N (0<<i
style="padding: 0px; margin: 0px;">N≤200000), which represents the number
of operations.

Each of the next N lines
containing an operation, as described above.

The last case is followed by a line containing one zero.

输出

For each case, print the case number (1, 2 …) first. Then, for each “find”
operation, output the result. Your output format should imitate the sample output. Print a blank line after each test case.

示例输入


4

add 2 3

find 1 2

remove 2 3

find 1 2
0

示例输出


Case 1:

2 3 
-1

用线段树维护每行的列的最大值,查找的时候就可以确定需要查找的set的位置,给的数虽然大,但是只有200000个操作,最多也就200000个数,所以可以先离线下来再离散处理一下
代码:
1、set的方法

[cpp] view plaincopyprint?
  1. #include<cstdio>
  2. #include<cstdlib>
  3. #include<cstring>
  4. #include<iostream>
  5. #include<algorithm>
  6. #include<string>
  7. #include<cmath>
  8. #include<queue>
  9. #include<map>
  10. #include<set>
  11. #include<vector>
  12. #define INF 999999
  13. #define mem(a,b) memset(a,b,sizeof(a))
  14. using namespace std;
  15. const int maxd=100;
  16. typedef long long ll;
  17. //typedef pair<int,int> info;
  18. typedef struct info
  19. {
  20. int x,y;
  21. friend bool operator<(info a,info b)
  22. {
  23. if(a.x==b.x) return a.y<b.y;
  24. return a.x<b.x;
  25. }
  26. } ;
  27. int main()
  28. {
  29. freopen("in.txt", "r", stdin);
  30. int n,x,y,kase=1;
  31. char str[maxd];
  32. set<info> s;
  33. while(scanf("%d",&n)!=EOF && n)
  34. {
  35. s.clear();
  36. printf("Case %d:\n",kase++);
  37. while(n--)
  38. {
  39. scanf("%s %d%d",str,&x,&y);
  40. info a={x,y};
  41. if(!strcmp(str,"add"))
  42. s.insert(a);
  43. else if(!strcmp(str,"remove"))
  44. {
  45. set<info>::iterator p=s.find({x,y});
  46. if(p!=s.end())
  47. s.erase(p);
  48. }
  49. else
  50. {
  51. set<info>::iterator p=s.lower_bound(a);
  52. if(p==s.end()) p=s.begin();
  53. for(p; p!=s.end(); ++p)
  54. if(p->first>x && p->second>y)
  55. {
  56. printf("%d %d\n",p->first,p->second);
  57. break;
  58. }
  59. if(p==s.end()) printf("-1\n");
  60. }
  61. }
  62. printf("\n");
  63. }
  64. return 0;
  65. }

2、set+线段树优化

[cpp] view
plain
copyprint?

  1. #include<cstdio>
  2. #include<cstdlib>
  3. #include<cstring>
  4. #include<iostream>
  5. #include<algorithm>
  6. #include<string>
  7. #include<cmath>
  8. #include<queue>
  9. #include<map>
  10. #include<set>
  11. #include<vector>
  12. #define INF 999999
  13. #define mem(a,b) memset(a,b,sizeof(a))
  14. using namespace std;
  15. const int maxd=200000+5;
  16. const int maxn=1000000000+5;
  17. typedef long long ll;
  18. typedef pair<int,int> pii;
  19. int n,x,y,kase=1,cnt,Num;
  20. char str[30];
  21. set<int> s[maxd];
  22. struct info
  23. {
  24. int x,y,z;
  25. } a[maxd];
  26. int b[maxd],maxv[maxd*2];
  27. int query(int num,int pos1,int l,int r,int o)///从pos1开始查找大于等于num
  28. {
  29. if(l==r)
  30. {
  31. if(maxv[o]>=num) return l;
  32. return -1;
  33. }
  34. int m= l+(r-l)/2,ans=-1;
  35. if(pos1<=m && maxv[o*2]>=num) ans=query(num,pos1,l,m,o*2);
  36. if(ans!=-1) return ans;
  37. if(maxv[o*2+1]>=num) ans=query(num,pos1,m+1,r,o*2+1);
  38. return ans;
  39. }
  40. void update(int p,int v,int l,int r,int o)///a[p]=v;
  41. {
  42. if(l==r) maxv[o]=v;
  43. else
  44. {
  45. int m=l+(r-l)/2;
  46. if(p<=m) update(p,v,l,m,o*2);
  47. else update(p,v,m+1,r,o*2+1);
  48. maxv[o]=max(maxv[o*2],maxv[o*2+1]);
  49. }
  50. }
  51. void init()
  52. {
  53. Num=0;
  54. mem(maxv,-1);
  55. for(int i=0; i<maxd; ++i)
  56. s[i].clear();
  57. printf("Case %d:\n",kase++);
  58. for(int i=0; i<n; ++i)
  59. {
  60. scanf("%s %d%d",str,&a[i].x,&a[i].y);
  61. if(!strcmp(str,"add"))
  62. {
  63. a[i].z=1;
  64. b[Num++]=a[i].x;
  65. }
  66. else if(!strcmp(str,"find"))
  67. a[i].z=2;
  68. else
  69. a[i].z=3;
  70. }///先离线下来
  71. cnt=1;
  72. for(int i=1; i<Num; ++i)
  73. {
  74. if(b[i]!=b[i-1])
  75. b[cnt++]=b[i];
  76. }///离散化处理
  77. sort(b,b+cnt);
  78. }
  79. void solve()
  80. {
  81. for(int i=0; i<n; ++i)
  82. if(a[i].z==1)///add
  83. {
  84. int pos=lower_bound(b,b+cnt,a[i].x)-b;
  85. // cout<<pos<<endl;
  86. s[pos].insert(a[i].y);
  87. update(pos,*(--s[pos].end()),0,cnt,1);
  88. }
  89. else if(a[i].z==2)///find
  90. {
  91. int pos=upper_bound(b,b+cnt,a[i].x)-b;
  92. if(pos==cnt)
  93. {
  94. printf("-1\n");
  95. continue;
  96. }
  97. int ans=query(a[i].y+1,pos,0,cnt,1);
  98. if(ans==-1) printf("-1\n");
  99. else printf("%d %d\n",b[ans],*(s[ans].lower_bound(a[i].y+1)));
  100. }
  101. else///remove
  102. {
  103. int pos=lower_bound(b,b+cnt,a[i].x)-b;
  104. s[pos].erase(a[i].y);
  105. if(s[pos].size()==0) update(pos,-1,0,cnt,1);
  106. else
  107. update(pos,*(--s[pos].end()),0,cnt,1);
  108. }
  109. }
  110. int main()
  111. {
  112. freopen("in.txt", "r", stdin);
  113. while(scanf("%d",&n)!=EOF && n)
  114. {
  115. init();
  116. solve();
  117. printf("\n");
  118. }
  119. return 0;
  120. }
时间: 2024-11-05 10:19:42

sdut-2159 Ivan comes again!(set+线段树)的相关文章

(山东省第一届省赛 I 题) SDUTOJ 2159 Ivan comes again! (线段树+set)

题目地址:SDUT 2159 这题的数据很水..几乎所有人都是水过去的..网上也没找到正解,全是水过去的.于是我来第一发正解23333. 首先,可以想到的是先离线下来,然后对行离散化,然后对于每行的所有列用set去存,那么怎么去找最小的行有大于给出列的列数呢?这时候线段树就可以登场了,用线段树来维护每一行的出现的最大列,这样就可以用线段树去搜了.然后删除添加操作同时在set与线段树中完成. 代码如下: #include <iostream> #include <string.h>

sdut 2159 Ivan comes again!(2010年山东省第一届ACM大学生程序设计竞赛) 线段树+离散

先看看上一个题: 题目大意是: 矩阵中有N个被标记的元素,然后针对每一个被标记的元素e(x,y),你要在所有被标记的元素中找到一个元素E(X,Y),使得X>x并且Y>y,如果存在多个满足条件的元素,先比较X,选择X最小的那个,如果还是有很多满足条件的元素,再比较Y,选择Y最小的元素,如果不存在就输出两个-1: 分析: 直接暴力就行了 这个题目大意: 这个题是上个题的坚强版,每次会增加或减少一个点,仍然找到一个元素E(X,Y),使得X>x并且Y>y: 最多有200000次操作,每次只

洛谷 P2253 好一个一中腰鼓 --线段树

P2253 好一个一中腰鼓 --线段树 题目背景 话说我大一中的运动会就要来了,据本班同学剧透(其实早就知道了),我萌萌的初二年将要表演腰鼓[喷],这个无厘头的题目便由此而来. Ivan乱入:“忽一人大呼:‘好一个安塞腰鼓!’满座寂然,无敢哗者,遂与外人间隔.” 题目描述 设想一下,腰鼓有两面,一面是红色的,一面是白色的.初二的苏大学神想给你这个oier出一道题.假设一共有N(1<=N<=20,000)个同学表演,表演刚开始每一个鼓都是红色面朝向观众,舞蹈老师会发出M(1<=M<=

[poj2104]可持久化线段树入门题(主席树)

解题关键:离线求区间第k小,主席树的经典裸题: 对主席树的理解:主席树维护的是一段序列中某个数字出现的次数,所以需要预先离散化,最好使用vector的erase和unique函数,很方便:如果求整段序列的第k小,我们会想到离散化二分和线段树的做法, 而主席树只是保存了序列的前缀和,排序之后,对序列的前缀分别做线段树,具有差分的性质,因此可以求任意区间的第k小,如果主席树维护索引,只需要求出某个数字在主席树中的位置,即为sort之后v中的索引:若要求第k大,建树时反向排序即可 1 #include

【BZOJ4942】[Noi2017]整数 线段树+DFS(卡过)

[BZOJ4942][Noi2017]整数 题目描述去uoj 题解:如果只有加法,那么直接暴力即可...(因为1的数量最多nlogn个) 先考虑加法,比较显然的做法就是将A二进制分解成log位,然后依次更新这log位,如果最高位依然有进位,那么找到最高位后面的第一个0,将中间的所有1变成0,那个0变成1.这个显然要用到线段树,但是复杂度是nlog2n的,肯定过不去. 于是我在考场上yy了一下,这log位是连续的,我们每次都要花费log的时间去修改一个岂不是很浪费?我们可以先在线段树上找到这段区间

bzoj1798: [Ahoi2009]Seq 维护序列seq 线段树

题目传送门 这道题就是线段树 先传乘法标记再传加法 #include<cstdio> #include<cstring> #include<algorithm> #define LL long long using namespace std; const int M=400010; LL read(){ LL ans=0,f=1,c=getchar(); while(c<'0'||c>'9'){if(c=='-') f=-1; c=getchar();}

Vijos P1066 弱弱的战壕【多解,线段树,暴力,树状数组】

弱弱的战壕 描述 永恒和mx正在玩一个即时战略游戏,名字嘛~~~~~~恕本人记性不好,忘了-_-b. mx在他的基地附近建立了n个战壕,每个战壕都是一个独立的作战单位,射程可以达到无限(“mx不赢定了?!?”永恒[email protected][email protected]). 但是,战壕有一个弱点,就是只能攻击它的左下方,说白了就是横纵坐标都不大于它的点(mx:“我的战壕为什么这么菜”ToT).这样,永恒就可以从别的地方进攻摧毁战壕,从而消灭mx的部队. 战壕都有一个保护范围,同它的攻击

luogu 1712 区间(线段树+尺取法)

题意:给出n个区间,求选择一些区间,使得一个点被覆盖的次数超过m次,最小的花费.花费指的是选择的区间中最大长度减去最小长度. 坐标值这么大,n比较小,显然需要离散化,需要一个技巧,把区间转化为半开半闭区间,然后线段树的每一个节点表示一个半开半闭区间. 接着我们注意到需要求最小的花费,且这个花费只与选择的区间集合中的最大长度和最小长度有关. 这意味着如果最大长度和最小长度一定,我们显然是需要把中间长度的区间尽量的选择进去使答案不会变的更劣. 不妨把区间按长度排序,枚举每个最小长度区间,然后最大区间

【BZOJ】1382: [Baltic2001]Mars Maps (线段树+扫描线)

1382: [Baltic2001]Mars Maps Time Limit: 5 Sec  Memory Limit: 64 MB Description 给出N个矩形,N<=10000.其坐标不超过10^9.求其面积并 Input 先给出一个数字N,代表有N个矩形. 接下来N行,每行四个数,代表矩形的坐标. Output 输出面积并 Sample Input 2 10 10 20 20 15 15 25 30 Sample Output 225 本以为是傻逼题,没想到不容易啊- 线段树+扫描