题目链接如下所示:
大意就是:
有个和尚战斗力1e9,id是1。输入n代表n个和尚,接下来n行每行一个id加战斗力,按空格分割。
输出就是找到在他入少林寺之前和他最近的战斗力和尚的id,然后把自身的id和对应找到的和尚id按行输出。
这里主要问题就是对战斗力排序,然后找到最近的那个战斗力的对应id,然后输出。
思路很简单,就是存一个
代码如下所示:
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- using namespace std;
-
- map<int, int> mp;
- int id,grade,ans;
-
- int main()
- {
- int n;
- while (~scanf("%d",&n) && n){
- mp.clear();
- mp[1000000000]=1;
- while (n--){
- scanf("%d %d",&id, &grade);
- mp[grade]=id;
- map<int, int>::iterator it=mp.find(grade);
- if (it==mp.begin()){
- ans=(++it)->second;
- }else{
- map<int, int>::iterator it2=it;
- it2--;
- it++;
- // cout<<"it:"<
second<<",it2:"<second< - ans = grade-it2->first <= it->first-grade ? it2->second : it->second;
- }
- printf("%d %d\n",id, ans);
- }
- }
- return 0;
- }
有篇博客把treap树讲的非常的清楚,包括了有旋treap的插入删除以及求前驱后继操作等等以及无旋treap树的合并与分裂操作。
数据结构-Treap(树堆) 详解_12362287的技术博客_51CTO博客
这里我们要做的其实就是treap的插入,由于有插入操作我们要维护堆,所以就要基于随机的优先级进行旋转,其次还要实现找到武功值为g的位次k,然后查找位次k-1,k+1的对应的武功值。
总的思路如下:
1.接受k,g,即id和武功值
2.维护id[g]=k,插入g到treap树中
3.查找g在树中的位次t
4.查找t-1,t+1位次对应的数值
5.输出答案
代码如下所示:
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- using namespace std;
-
- const int N=5000001;
- int id[N];
- struct Node{
- int size;//以当前节点为根的子树的大小
- int rank;//用以维护treap的随机数
- int key;//键值 这里是武功级别
- Node *son[2];
- // 小于比较 自身rank和传入的rank
- bool operator < (const Node &a) const{
- return rank
- }
- // 比较x和自身key
- // 相等返回-1
- // x
- // x>key 右子树 1
- int cmp(int x) const{
- if (key==x) return -1;
- return x
0:1; - }
- // 更新子树的大小 旋转时treap存在节点需要更新子树大小
- void update(){
- size=1;
- if (son[0]) size+=son[0]->size;
- if (son[1]) size+=son[1]->size;
- }
- };
-
- // 旋转 d=0左旋 d=1右旋
- void rotate(Node* &o,int d){
- Node *k=o->son[1^d];
- o->son[1^d]=k->son[d];
- k->son[d]=o;
- o->update();
- k->update();
- o=k;//这里把原来指向o的位置改了 所以原来指向o的指针现在相当于指向k 也是传指针的引用的原因
- }
-
- void insert(Node* &o, int x){
- if (!o){
- o=new Node();//直接在原位置创建指针 这是穿指针的引用的原因
- o->son[0]=o->son[1]=nullptr;
- o->rank=rand();
- o->key=x;
- o->size=1;
- }else{
- int d=o->cmp(x);
- insert(o->son[d],x);
- o->update();
- if (o
son[d]){ - rotate(o,1^d);
- }
- }
- }
-
- // 返回第k大的数
- int kth(Node* o, int k){
- if (o== nullptr||k<0 || k>o->size){
- return -1;
- }
- int s= (o->son[1] == nullptr) ? 0 : o->son[1]->size;
- if (k==s+1) return o->key;
- else if (k
1){ - return kth(o->son[1], k);
- }else{
- return kth(o->son[0],k-s-1);
- }
- }
-
- // 找到k的位次
- int find(Node* o, int k){
- if (!o) return -1;
- int d=o->cmp(k);
- if (d==-1){
- return o->son[1] == nullptr ? 1 : o->son[1]->size+1;
- }else if (d==1){
- return find(o->son[1], k);
- }else{
- int tmp=find(o->son[0], k);
- if (tmp==-1) return -1;
- return o->son[1] == nullptr ? tmp+1 : tmp+o->son[1]->size+1;
- }
- }
-
- void deleteNode(Node *root){
- if (!root) return;
- deleteNode(root->son[0]);
- deleteNode(root->son[1]);
- delete root;
- }
-
- int main()
- {
- int n;
- while (scanf("%d", &n) && n){
- srand(time(nullptr));
- int k,g;
- Node *root = new Node();
- scanf("%d %d",&k,&g);
- // cout<
- id[g]=k;
- root->son[0]=root->son[1]=nullptr;
- root->key=g;
- root->size=1;
- root->rank=rand();
- printf("%d %d\n",k,1);
- for (int i = 2; i <= n; ++i) {
- scanf("%d %d",&k,&g);
- // cout<
- id[g]=k;
- // cout<<0<
- insert(root, g);
- // cout<<1<
- int t= find(root, g);
- // cout<<2<
- int ans,ans1,ans2;
- ans1=kth(root, t-1);
- ans2=kth(root, t+1);
- if (ans1!=-1 && ans2!=-1){
- ans= ans1-g >= g-ans2 ? ans2 : ans1;
- }else if (ans1==-1){
- ans=ans2;
- }else{
- ans=ans1;
- }
- printf("%d %d\n", k,id[ans]);
- }
- deleteNode(root);
- }
- return 0;
- }