华师一附中OI组

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 1593|回复: 6
打印 上一主题 下一主题

P1097 统计数字

[复制链接]

738

主题

1485

帖子

5422

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
5422
跳转到指定楼层
楼主
发表于 2018-4-19 11:26:13 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
https://www.luogu.com.cn/problem/P1097
题目描述
某次科研调查时得到了n个自然数,每个数均不超过1500000000(1.5*10^9)。已知不相同的数不超过10000个,现在需要统计这些自然数各自出现的次数,并按照自然数从小到大的顺序输出统计结果。

输入输出格式
输入格式:
输入文件count.in包含n+1行;

第一行是整数n,表示自然数的个数;

第2~n+1每行一个自然数。

输出格式:
输出文件count.out包含m行(m为n个自然数中不相同数的个数),按照自然数从小到大的顺序输出。每行输出两个整数,分别是自然数和该数出现的次数,其间用一个空格隔开。

输入输出样例
输入样例#1:
8
2
4
2
4
5
100
2
100

输出样例#1:
2 3
4 2
5 1
100 2
说明
40%的数据满足:1<=n<=1000

80%的数据满足:1<=n<=50000

100%的数据满足:1<=n<=200000,每个数均不超过1500 000 000(1.5*109)

NOIP 2007 提高第一题
回复

使用道具 举报

9

主题

158

帖子

470

积分

华一学生

积分
470
QQ
沙发
发表于 2018-9-9 10:28:22 | 只看该作者
  1. #include<iostream>
  2. #include<map>
  3. using namespace std;
  4. int n,a;
  5. map<int,int>m;
  6. map<int,int>::iterator it;
  7. int main()
  8. {
  9.     cin>>n;
  10.     for(int i=1;i<=n;i++)
  11.     {
  12.         cin>>a;
  13.         m[a]++;
  14.     }
  15.     for(it=m.begin();it!=m.end();it++)
  16.         cout<<it->first<<' '<<it->second<<endl;
  17.     return 0;
  18. }
复制代码
回复 支持 反对

使用道具 举报

738

主题

1485

帖子

5422

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
5422
板凳
 楼主| 发表于 2020-3-15 18:31:31 | 只看该作者
楼上的做法好巧妙呀。现在我们用这个题来训练BST,Scapegoat Tree,Treap,Splay,等
回复 支持 反对

使用道具 举报

738

主题

1485

帖子

5422

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
5422
地板
 楼主| 发表于 2020-3-15 18:34:11 | 只看该作者
先来抛转引玉,没有写好的裸的BST,测试数据很值得一看。
  1. #include <iostream>
  2. using namespace  std;
  3. struct BSTnode
  4. {
  5.     int data;
  6.     int cnt;
  7.     BSTnode *l,*r;
  8. } *T;
  9. void BSTins(BSTnode *&bst, int x) ///把x插入到bst树中
  10. {
  11.     if (bst==NULL)   ///
  12.     {
  13.         BSTnode *p=new BSTnode;
  14.         p->data=x;
  15.         p->cnt=1;
  16.         p->l=p->r=NULL;
  17.         bst=p;
  18.     }
  19.     else if (x<bst->data) BSTins(bst->l,x);
  20.     else if (x>bst->data) BSTins(bst->r,x);
  21.     else if (x==bst->data) bst->cnt++;
  22. }
  23. void inorder(BSTnode *bst)
  24. {
  25.     if (bst!=NULL)
  26.     {
  27.         inorder(bst->l);
  28.         cout<<bst->data<<' ';///<<bst->cnt<<'\t';
  29.         inorder(bst->r);
  30.     }
  31. }
  32. BSTnode * BSTfind(BSTnode * bst, int x)
  33. {
  34.     if (bst==NULL)  return NULL;
  35.     else if (bst->data==x) return bst;
  36.     else if (bst->data>x) return BSTfind(bst->l, x);
  37.     else if (bst->data<x) return BSTfind(bst->r, x);
  38. }
  39. bool BSTdel(BSTnode * & bst,int x)
  40. {
  41.     if (bst==NULL) return 0;   ///没有这个数,删除未成功
  42.     else if (bst->data>x) return BSTdel(bst->l,x);
  43.     else if (bst->data<x) return BSTdel(bst->r,x);
  44.     else  if (bst->cnt>1) {bst->cnt--;return 1;}  ///存在这个数,减1
  45.     {
  46.         ///BSTnode *p=bst;
  47.         if (bst->l==NULL)   ///没有左子树就直接把右子树接上来
  48.         {
  49.             bst=bst->r;
  50.             ///del(p);
  51.             return 1;
  52.         }
  53.         else  if (bst->r==NULL)  ///没有右子树就直接把左子树接上来
  54.         {
  55.             bst=bst->l;
  56.             ///del(p);
  57.             return 1;
  58.         }
  59.         else
  60.         {
  61.             if (bst->l->r==NULL)   //左儿子没有右儿子
  62.             {
  63.                 bst->data=bst->l->data;
  64.                 bst->cnt=bst->l->cnt;
  65.                 return BSTdel(bst->l,bst->l->data);
  66.             }
  67.             else
  68.             {  /// 这里有问题 没写好
  69.                 BSTnode *p1=bst, *p2=bst->l;
  70.                 while (p2->r==NULL)
  71.                 {
  72.                     p1=p2;
  73.                     p2=p2->r;
  74.                 }
  75.                 bst->data=p2->data;
  76.                 bst->cnt=p2->cnt;
  77.                 return BSTdel(p1->r,p2->data);
  78.             }
  79.         }

  80.     }
  81. }
  82. int main()
  83. {
  84.     int x;
  85.     cin>>x;
  86.     while (x>0)
  87.     {
  88.         BSTins(T,x);
  89.         cin>>x;
  90.     }
  91.     inorder(T);cout<<endl;
  92.     cin>>x;
  93.     while (x>0)  /// 删除
  94.     {
  95.         BSTdel(T,x);
  96.         inorder(T);
  97.         cout<<endl;
  98.         cin>>x;
  99.     }
  100.   return 0;
  101. }
  102. /*
  103. 50 25 75 18 38 66 80 10 16 26 40 62 68 79 90 9 12 15 30 42 93 8 14 41 43 95 6 44 94 99 5 7 0

  104. */
复制代码
回复 支持 反对

使用道具 举报

1

主题

6

帖子

82

积分

注册会员

Rank: 2

积分
82
5#
发表于 2020-4-5 20:37:51 | 只看该作者
输出的顺序错了,不知道为什么
  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. const int SIZE=1e6+9;
  4. const int inf=1<<30;
  5. struct Treap{int l,r,val,dat,cnt,size;}a[SIZE];
  6. int tot,root,n;
  7. inline int New(int val){
  8.         a[++tot].val=val;
  9.         a[tot].dat=rand();
  10.         a[tot].cnt=a[tot].size=1;
  11.         return tot;
  12. }
  13. inline void Update(int p){
  14.         a[p].size=a[a[p].l].size+a[a[p].r].size+a[p].cnt;
  15. }
  16. inline void Build(){
  17.         New(-inf),New(inf);
  18.         root=1,a[1].r=2;
  19.         Update(root);
  20. }
  21. inline void zig(int &p){
  22.         int q=a[p].l;
  23.         a[p].l=a[q].r,a[q].r=p,p=q;
  24.         Update(a[p].r),Update(p);
  25. }
  26. inline void zag(int &p){
  27.         int q=a[p].r;
  28.         a[p].r=a[q].l,a[q].l=p,p=q;
  29.         Update(a[p].l),Update(p);
  30. }
  31. void Insert(int &p,int val){
  32.         if(p==0) return p=New(val),void();
  33.         if(val==a[p].val) return a[p].cnt++,Update(p),void();
  34.         if(val<a[p].val){
  35.                 Insert(a[p].l,val);
  36.                 if(a[p].dat<a[a[p].l].dat) zig(p);
  37.         }
  38.         else{
  39.                 Insert(a[p].r,val);
  40.                 if(a[p].dat<a[a[p].r].dat) zag(p);
  41.         }
  42.         Update(p);
  43. }
  44. inline int GetPre(int val){
  45.         int ans=1;
  46.         int p=root;
  47.         while(p){
  48.                 if(val==a[p].val){
  49.                         if(a[p].l>0){
  50.                                 p=a[p].l;
  51.                                 while(a[p].r>0) p=a[p].r;
  52.                                 ans=p;
  53.                         }
  54.                         break;
  55.                 }
  56.                 if(a[p].val<val&&a[p].val>a[ans].val) ans=p;
  57.                 p=(val<a[p].val)?a[p].l:a[p].r;
  58.         }
  59.         return a[ans].val;
  60. }
  61. inline int GetNext(int val){
  62.         int ans=2;
  63.         int p=root;
  64.         while(p){
  65.                 if(val==a[p].val){
  66.                         if(a[p].r>0){
  67.                                 p=a[p].r;
  68.                                 while(a[p].l>0) p=a[p].l;
  69.                                 ans=p;
  70.                         }
  71.                         break;
  72.                 }
  73.                 if(a[p].val>val&&a[p].val<a[ans].val) ans=p;
  74.                 p=(val<a[p].val)?a[p].l:a[p].r;
  75.         }
  76.         return a[ans].val;
  77. }
  78. int GetRankByVal(int p,int val){
  79.         if(p==0) return 0;
  80.         if(val==a[p].val) return a[a[p].l].size+1;
  81.         if(val<a[p].val) return GetRankByVal(a[p].l,val);
  82.         return GetRankByVal(a[p].r,val)+a[a[p].l].size+a[p].cnt;
  83. }
  84. int GetValByRank(int p,int rank){
  85.         if(p==0) return inf;
  86.         if(a[a[p].l].size>=rank) return GetValByRank(a[p].l,rank);
  87.         if(a[a[p].l].size+a[p].cnt>=rank) return a[p].val;
  88.         return GetValByRank(a[p].r,rank-a[a[p].l].size-a[p].cnt);
  89. }
  90. void Remove(int &p,int val){
  91.         if(p==0) return;
  92.         if(val==a[p].val){
  93.                 if(a[p].cnt>1){
  94.                         a[p].cnt--,Update(p);
  95.                         return;
  96.                 }
  97.                 if(a[p].l||a[p].r){
  98.                         if(a[p].r==0||a[a[p].l].dat>a[a[p].r].dat) zig(p),Remove(a[p].r,val);
  99.                         else zag(p),Remove(a[p].l,val);
  100.                         Update(p);
  101.                 }
  102.                 else p=0;
  103.                 return;
  104.         }
  105.         (val<a[p].val)?Remove(a[p].l,val):Remove(a[p].r,val);
  106.         Update(p);
  107. }
  108. void middle_traval(int x){
  109.         if(x<=0||x>1500000000) return;
  110.         cout<<a[x].val<<" "<<a[x].cnt<<'\n';
  111.         middle_traval(a[x].l);
  112.         middle_traval(a[x].r);
  113. }
  114. int main(){
  115.         srand((unsigned)time(NULL));
  116.         ios::sync_with_stdio(0);
  117.         Build();
  118.         cin>>n;
  119.         for(int i=1;i<=n;++i){
  120.                 int x;
  121.                 cin>>x;
  122.                 Insert(root,x);
  123.         }
  124.         Remove(root,-inf),Remove(root,inf);
  125.         middle_traval(root);
  126. //        while(n--){
  127. //                int opt,x;
  128. //                cin>>opt>>x;
  129. //                if(opt==1) Insert(root,x);
  130. //                else if(opt==2) Remove(root,x);
  131. //                else if(opt==3) cout<<GetRankByVal(root,x)-1<<'\n';
  132. //                else if(opt==4) cout<<GetValByRank(root,x+1)<<'\n';
  133. //                else if(opt==5) cout<<GetPre(x)<<'\n';
  134. //                else if(opt==6) cout<<GetNext(x)<<'\n';
  135. //        }
  136.         return 0;
  137. }
复制代码
回复 支持 反对

使用道具 举报

738

主题

1485

帖子

5422

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
5422
6#
 楼主| 发表于 2020-4-5 20:38:35 | 只看该作者
来一个裸的SPLAY的,用来训练SPALY的插入和旋转
  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. const int inf=9999999;
  4. const int N=100100;
  5. struct node
  6. {
  7.         int val,cnt;
  8.         int fa,s[2],sz;  ///s0s1左右儿子
  9. } a[N];
  10. int n, tot, root;
  11. void ArrayPr()   /// 调试监视使用
  12. {
  13.         cout<<endl<<"  i ";
  14.         for (int i=1; i<=tot; i++) cout<<setw(3)<<i;
  15.         cout<<endl<<"val ";
  16.         for (int i=1; i<=tot; i++) cout<<setw(3)<<a[i].val;
  17.         cout<<endl<<"cnt ";
  18.         for (int i=1; i<=tot; i++) cout<<setw(3)<<a[i].cnt;
  19.         cout<<endl<<" s0 ";
  20.         for (int i=1; i<=tot; i++) cout<<setw(3)<<a[i].s[0];
  21.         cout<<endl<<" s1 ";
  22.         for (int i=1; i<=tot; i++) cout<<setw(3)<<a[i].s[1];
  23.         cout<<endl<<" sz ";
  24.         for (int i=1; i<=tot; i++) cout<<setw(3)<<a[i].sz;
  25.         cout<<endl;
  26. }

  27. void BSTPr(int rt)   ///中序输出以rt为根的BST
  28. {
  29.         if (a[rt].s[0]>0)  BSTPr(a[rt].s[0]);
  30.         cout<<a[rt].val<<' '<<a[rt].cnt<<endl;
  31.         if (a[rt].s[1]>0)  BSTPr(a[rt].s[1]);
  32. }
  33. void pushup(int rt)   ///类似线段树网上调整
  34. {
  35.         int l=a[rt].s[0], r=a[rt].s[1];
  36.         a[rt].sz=a[l].sz+a[r].sz+a[rt].cnt;
  37. }
  38. void LR(int rt)/// 左旋 因为有了fa,所以不需要传地址 但是也多了修改fa指针的操作
  39. {
  40.         ///cout<<"L\n";
  41.         int x=a[rt].fa; ///x是rt的爸爸
  42.         int y=a[x].fa;///y是x的爸爸 rt的爷爷
  43.         int l=a[rt].s[0];
  44.         a[x].s[1]=l;///rt的左儿子挂给x当右儿子(本来右儿子是rt)
  45.         if(l!=0) a[l].fa=x;        //这个要注意空节点没有fa

  46.         a[rt].fa=y; //rt取代了他的爸爸x
  47.         a[rt].s[0]=x;//rt的原父节点x成为rt 的左儿子
  48.         if(y!=0)
  49.                 {
  50.                         if(x==a[y].s[0])
  51.                                 a[y].s[0]=rt;
  52.                         else a[y].s[1]=rt;
  53.                 }
  54.         a[x].fa=rt;
  55.         pushup(x),pushup(rt);
  56. }

  57. void RR(int rt) /// 同上 右旋
  58. {
  59.         ///cout<<"R\n";
  60.         int x=a[rt].fa; ///x是rt的爸爸
  61.         int y=a[x].fa;///y是x的爸爸 rt的爷爷
  62.         int  r=a[x].s[0]=a[rt].s[1];
  63.         if(r!=0) a[r].fa=x;

  64.         a[rt].fa=y; //rt取代了他的爸爸x
  65.         a[rt].s[1]=x;
  66.         if(y!=0)
  67.                 {
  68.                         if(x==a[y].s[0])
  69.                                 a[y].s[0]=rt;
  70.                         else a[y].s[1]=rt;
  71.                 }
  72.         a[x].fa=rt;        pushup(x),pushup(rt);
  73. }

  74. void splay(int rt)//伸展操作: 6种情况
  75. {
  76.         int x,y;
  77.         while(a[rt].fa!=0)//反复进行旋转,直至将x节点调整至根部为止
  78.                 {
  79.                         x=a[rt].fa;///rt的爸爸
  80.                         y=a[x].fa;
  81.                         if(y==0)//在x为根的情况下,若x在左儿子位置,则右旋;否则左旋
  82.                                 {
  83.                                         if(rt==a[x].s[0]) RR(rt);
  84.                                         else LR(rt);
  85.                                         break;
  86.                                 }
  87.                     
  88.                         if(rt==a[x].s[0])//在x位于左位置的情况下,若x的父节点位于左位置,则分别
  89.                                 //以x的父节点和x为基准两次右旋;否则以x为基准右旋和左旋
  90.                                 {
  91.                                         if(x==a[y].s[0])  ///LLL
  92.                                                 {
  93.                                                         RR(x);
  94.                                                         RR(rt);
  95.                                                 }
  96.                                         else  ///LLR
  97.                                                 {
  98.                                                         RR(rt);
  99.                                                         LR(rt);
  100.                                                 }
  101.                                 }
  102.                         else
  103.                                 {
  104.                                         if(x==a[y].s[1]) ///RRR
  105.                                                 {
  106.                                                         LR(x);
  107.                                                         LR(rt);
  108.                                                 }
  109.                                         else
  110.                                                 {
  111.                                                         LR(rt);
  112.                                                         RR(rt);
  113.                                                 }
  114.                                 }
  115.                 }
  116.         root=rt;//新根
  117.         //cout<<rt<<endl;
  118. }
  119. void Ins(int rt, int x)   /// 在rt子树中插入x
  120. {
  121.         if(rt==0)  /// 新树
  122.                 {
  123.                         tot=root=1;
  124.                         a[1].fa=a[1].s[0]=a[1].s[1]=0;
  125.                         a[1].val=x;
  126.                         a[1].cnt=1;
  127.                 }
  128.         else if(a[rt].val==x) a[rt].cnt++;
  129.         else if(a[rt].val<x)
  130.                 {
  131.                         if (a[rt].s[1]==0)
  132.                                 {
  133.                                         a[rt].s[1]=++tot;
  134.                                         a[tot].s[0]=a[tot].s[1]=0;
  135.                                         a[tot].val=x;
  136.                                         a[tot].fa=rt;
  137.                                         a[tot].cnt=1;
  138.                                         splay(tot);
  139.                                 }
  140.                         else
  141.                                 Ins(a[rt].s[1],x);
  142.                 }
  143.         else if(a[rt].val>x)
  144.                 {
  145.                         if (a[rt].s[0]==0)
  146.                                 {
  147.                                         a[rt].s[0]=++tot;
  148.                                         a[tot].s[0]=a[tot].s[1]=0;
  149.                                         a[tot].val=x;
  150.                                         a[tot].fa=rt;
  151.                                         a[tot].cnt=1;
  152.                                         splay(tot);
  153.                                 }
  154.                         else
  155.                                 Ins(a[rt].s[0], x);
  156.                 }

  157. }

  158. int main()
  159. {
  160.         cin>>n;
  161.         while(n--)
  162.                 {
  163.                         int x;
  164.                         cin>>x;
  165.                         Ins(root,x);

  166.                 }
  167.         BSTPr(root);
  168.         return 0;
  169. }
复制代码
回复 支持 反对

使用道具 举报

738

主题

1485

帖子

5422

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
5422
7#
 楼主| 发表于 2020-4-5 20:52:49 | 只看该作者
第110行左右的输出语句顺序有问题。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|小黑屋|服务支持:DZ动力|华师一附中OI组  

GMT+8, 2024-12-26 15:00 , Processed in 0.122887 second(s), 23 queries .

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表