天津大学2010年区域赛1007 Giant For

这题典型的线段树加离散化,比赛的时候没有思路,中午突然想到了怎么实现。

这题主要的思路是将全部的数据读取进来然后离线处理,离散化的时候把不同的点按照先x后y的方式离散化,也就是说只要两个点不是同一个点,那么他们的离散化后的hash值就不一样,将离散化后的值放到lst数组中去。

在线段树中维护第i个lst元素是否存在,如果存在,那么线段树中的第i个元素值就是lst[i]对应的y值,否则就为-1,seg的值记录[l,r]区间的最大值。每次find的时候,读取的如果是x,y,那么去找[x+1,M]区间,优先找左边的区间,如果左边区间的最大值比y来的大,那么解一定在左边区间,如果左边区间的最大值小于或等于y,那么用同样的方法找右区间,如果依然没有比y大的,那么返回-1,否则返回第一个比y大的区间在lst数组中对应的脚标。

 

主要是离散化的方式有点特别,先按xy排序,记录lst数组,然后按id排序,返回原来输入的顺序,这样保证了读取的顺序和输入顺序一致。

 

我的代码:

 

#include <iostream> #include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> using namespace std; const int MAX=200100; struct Lst { int x,y; }lst[MAX]; struct Node { int op; int x,y; int id; int val; int nxt; }node[MAX]; int n,M; int seg[4*MAX]; bool comp1(const Node& a,const Node& b) { if(a.x!=b.x) return a.x<b.x; else return a.y<b.y; } bool comp2(const Node& a,const Node& b) { return a.id<b.id; } void hash() { for(int i=0;i<n;i++) node[i].id=i; sort(node,node+n,comp1); M=1; node[0].val=M; lst[M].x=node[0].x; lst[M].y=node[0].y; for(int i=1;i<n;i++) { if(node[i].x==node[i-1].x&&node[i].y==node[i-1].y) node[i].val=M; else { node[i].val=++M; lst[M].x=node[i].x; lst[M].y=node[i].y; } } node[n-1].nxt=-1; for(int i=n-2;i>=0;i--) { if(node[i].x!=node[i+1].x) node[i].nxt=node[i+1].val; else node[i].nxt=node[i+1].nxt; } sort(node,node+n,comp2); } void init(int k,int l,int r) { if(l==r) { seg[k]=0; return; } int mid=(l+r)/2; init(2*k,l,mid); init(2*k+1,mid+1,r); seg[k]=0; } void update(int k,int l,int r,int idx,int v) { if(l==r) { seg[k]=v; return; } int mid=(l+r)/2; if(idx<=mid) update(2*k,l,mid,idx,v); else update(2*k+1,mid+1,r,idx,v); seg[k]=max(seg[2*k],seg[2*k+1]); } int read(int k,int l,int r,int a,int b,int v) { int tmp; int mid=(l+r)/2; if(l>b||r<a) return -1; if(seg[k]<=v) return -1; if(l==r) return l; if(l>=a&&r<=b) { if(seg[2*k]>v) return read(2*k,l,mid,a,b,v); else return read(2*k+1,mid+1,r,a,b,v); } tmp=read(2*k,l,mid,a,b,v); if(tmp>=0) return tmp; tmp=read(2*k+1,mid+1,r,a,b,v); if(tmp>=0) return tmp; return -1; } int main() { char op[100]; int id; int cnt=1; while(scanf("%d",&n),n) { if(cnt!=1) printf("/n"); for(int i=0;i<n;i++) { scanf("%s%d%d",op,& node[i].x,&node[i].y); if(op[0]=='a') node[i].op=1; else if(op[0]=='r') node[i].op=2; else node[i].op=3; } hash(); init(1,1,M); printf("Case %d:/n",cnt++); for(int i=0;i<n;i++) { switch(node[i].op) { case 1: update(1,1,M,node[i].val,node[i].y); break; case 2: update(1,1,M,node[i].val,-1); break; case 3: if(node[i].nxt<0) { printf("-1/n"); break; } id=read(1,1,M,node[i].nxt,M,node[i].y); if(id<0) printf("-1/n"); else printf("%d %d/n",lst[id].x,lst[id].y); break; } } } return 0; }

 

看来还是见世面见的太少了,很多算法没有思路。

 

你可能感兴趣的:(算法,struct,ini,2010)