Giant For
Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1397 Accepted Submission(s): 261
Problem DescriptionIt is known to us all that YY and LMY are mathematics lovers. They like to find and solve interesting mathematic problems together. Now LMY designs a game for matrix. There is a large matrix whose rows and columns are both not more than 1000000000. And there are three operations for the matrix:
1)
add: Mark an element in the matrix. It is guaranteed that the element has not been marked before.
2)
remove: Delete an element’s mark. It is guaranteed that the element has been marked before.
3)
find: For a given element’s row and column, return a marked element’s row and column, where the marked element’s row and column are larger than the given 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.
LMY lets YY develop a program to solve the problem. Could you also develop a program to solve the problem?
InputThe input consists of multiple test cases. For each test case, the first line contains only one integer n. n ≤ 200000. Each of the next n lines describes an operation. There is a blank line between two consecutive test cases.
End of input is indicated by a line containing a zero.
OutputStart each test case with "Case #:" on a single line, where # is the case number starting from 1. For each “find” operation, output the result. The format is showed as sample output. There is a blank line between two consecutive test cases.
Sample Input
5add 48 1add 25 69add 88 52remove 25 69add 23 8910add 47 23find 66 83find 27 73add 84 97find 10 58remove 47 23add 41 89remove 41 89find 65 68add 25 410
Sample Output
Case 1:Case 2:-1-184 9784 97
SourceThe 35th ACM/ICPC Asia Regional Tianjin Site —— Online Contest 2010天津網路預選賽1007題目ps:當時沒學線段樹,一看資料這麼大就蒙了,現在學了線段樹就做了起來。效率還不錯1548ms AC線段樹的資料:請參考http://blog.csdn.net/Hashmat/archive/2010/09/28/5911369.aspx/*</p><p>題目大意:不超過*1000000000的矩陣,三個操作。add 插入(xi,yi);remove 移除 (xi,yi);find 尋找(>xi,>yi)的最小值<br />題目解答:n=1000000000 太大超過 int 的範圍<br />:op_num(運算元) = 200000 也就是最多有op_num對數值 所以離散成 hash[op_num]然後再用線段樹統計</p><p>Problem : 3627 ( Giant For ) Judge Status : Accepted<br />RunId : 3007530 Language : C++ Author : wawadimu<br />Code Render Status : Rendered By HDOJ C++ Code Render Version 0.01 Beta<br />*/<br />#include<iostream><br />#include<algorithm><br />using namespace std;</p><p>#define N 200010</p><p>//運算元組<br />char op[N][7];</p><p>//原數組,排序數組,離散後數組</p><p>struct node<br />{<br />int row,col;<br />}res[N],tmp[N],hash[N];</p><p>// 線段樹<br />struct tr<br />{<br />int l,r,max_col;<br />}tree[3*N];</p><p>//按行升序排列<br />int cmp( const node &a , const node &b)<br />{<br />if( a.row != b.row ) return a.row < b.row;<br />else return a.col < b.col ;<br />}</p><p>//在區間[L,R]內尋找p的次序<br />int query(node p , int L , int R);<br />//建立線段樹<br />void built(int l, int r , int num);<br />//更新區間[cnt,cnt]<br />void insert(node p, int cnt , int num);<br />//移除區間[cnt,cnt];<br />void remove(node p, int cnt ,int num);<br />//尋找區間[L,R]內比L大的節點<br />int find(node p , int L ,int R , int num);</p><p>int main()<br />{<br />freopen("3627.txt","r",stdin);<br />int n;<br />int i,j,k;<br />int c=1;<br />while(scanf("%d",&n)!=EOF && n!=0)<br />{<br />if( c != 1) printf("/n");<br />printf("Case %d:/n",c++);<br />for(i=1; i<=n; i++)<br />{<br />scanf("%s%d%d",op[i], &res[i].row, &res[i].col);<br />tmp[i].row=res[i].row; tmp[i].col=res[i].col;<br />}<br />sort(tmp+1,tmp+n+1,cmp);//排序<br />k=0;<br />tmp[0].col=-N; tmp[0].row=-N;<br />for(i=1; i<=n; i++)//離散<br />{<br />if( tmp[i].row == tmp[i-1].row && tmp[i].col == tmp[i-1].col) continue;<br />else<br />{ //cout<<tmp[i].row<<"->"<<tmp[i].col<<" ";<br />hash[++k].col=tmp[i].col;<br />hash[k].row=tmp[i].row;<br />}<br />}<br />//cout<<k<<endl;<br />built(1 , k , 1 );<br />for(i=1; i<=n; i++)<br />{<br />int cnt=query( res[i] , 1 , k); //尋找res[i]在離散後的數組的位置hash[cnt]<br />//cout<<cnt<<" ";<br />if( strcmp( op[i] ,"add") == 0) insert( res[i] , cnt ,1 );<br />else if(strcmp( op[i] , "remove") == 0) remove( res[i] , cnt ,1 );<br />else {<br />int ans=find( res[i] , cnt , k , 1 );//找到返回區間值[ans,ans],否則返回-1<br />if( ans ==-1 ) printf("-1/n");<br />else printf("%d %d/n",hash[ans].row,hash[ans].col);<br />}<br />}<br />}<br />return 0;<br />}<br />void built( int l , int r , int num)//建立單點的區間<br />{<br />tree[num].l=l; tree[num].r= r; tree[num].max_col=0;<br />//cout<<num<<" :"<<l<<"->"<<r<<" ";<br />if(l<r)<br />{<br />int m=( l + r ) >> 1;<br />built( l , m , 2*num );<br />built( m+1 , r, 2*num+1 );//m+1<br />}<br />}<br />int query(node p , int L , int R)<br />{<br />int l=L , r=R ;<br />int t = p.row;<br />//<br />//由於可以出現行重疊的情況,所以尋找比他row大的數字,然後反推比較確定值的位置<br />//<br />while( l <= r)<br />{<br />int mid=( l + r ) >> 1;<br />if( t >= hash[mid].row )<br />l= mid + 1;<br />else r= mid -1;<br />}<br />//反向比較,確定位置<br />while(--l)<br />{<br />if(hash[l] .col == p.col )<br />break;<br />}<br />return l;<br />}<br />void insert( node p, int cnt , int num)<br />{<br />if( tree[num].l == tree[num].r )//葉子節點,插入<br />{<br />//cout<<tree[num].l<<"->"<<p.col<<" ";<br />tree[num].max_col = p.col;<br />return ;<br />}<br />//cout<<num<<" ";<br />int mid=( tree[num].l + tree[num].r ) >> 1;<br />if( cnt <= mid ) insert( p , cnt , 2*num );<br />else insert( p , cnt , 2*num + 1);<br />//父親節點儲存子樹y的最大值,有利於降低尋找的效率<br />tree[num].max_col = tree[2*num].max_col > tree[2*num+1].max_col ? tree[2*num].max_col : tree[2*num+1].max_col;<br />}<br />void remove( node p, int cnt , int num)<br />{<br />if( tree[num].l == tree[num].r )<br />{<br />//cout<<tree[num].l<<"->"<<p.col<<" ";<br />tree[num].max_col = 0;<br />return ;<br />}<br />//cout<<cnt<<num<<" ";<br />int mid=( tree[num].l + tree[num].r ) >> 1;<br />if( cnt <= mid ) remove( p , cnt , 2*num );<br />else remove( p , cnt , 2*num + 1);<br />}<br />int find( node p , int L , int R ,int num)<br />{<br />int tmp;<br />if( tree[num].max_col < p.col ) return -1;<br />if( tree[num].l == tree[num].r )<br />{//tree[num].max_col > p.col && tree[num].l > L cout<<tree[num].l<<">"<<L<<" ";<br />if( hash[tree[num].l].row > p.row && hash[tree[num].r].col > p.col )//這裡比較實際值的大小不是離散值大小,因為這裡WA了.<br />{</p><p>return tree[num].l;<br />}<br />else return -1;<br />}<br />int mid = ( tree[num].l + tree[num].r ) >> 1;<br />//<br />//如果覆蓋兩個子領域,先找左區間是否有符合的值,然後尋找右區間的情況<br />//<br />if( L < mid )<br />{<br />//cout<<2*num<<" ";<br /> tmp = find( p, L , R, 2*num );<br />if( tmp != -1 ) return tmp;<br />}<br />if( R >= mid )<br />{<br />//cout<<2*num+1<<" ";<br />tmp=find( p, L , R, 2*num + 1 );<br />if( tmp != -1 ) return tmp;<br />}<br />return -1;<br />}<br />