• BZOJ1056 [HAOI2008]排名系统 treap实现map


    需要的功能:

    ①更新一个字符串对应的最新分数

    ②获得一个字符串对应的最新分数

    ③获得平衡树中第几名

    hint是哈希,感觉没什么头绪。。

    题解存下了字符串和一个哈希内存池,用链式前向星处理hash冲突,用时间戳作为第二比较关键字,在分数相同时检索时间戳

    具体来说就是在查询一个字符串时,先在哈希内存池顺着前向星用字符串匹配找到时间戳,

    再用分数和时间戳的关键字从treap中找到对应信息(适合题目的较早信息有高rank的设定)

    这题核心就在于把时间戳作为第二关键字的运用可以实现简单的map,以及哈希内存池的设置,这些在以前我都没见过。。

    #include<bits/stdc++.h>  
    //#pragma comment(linker, "/STACK:1024000000,1024000000")   
    #include<stdio.h>  
    #include<algorithm>  
    #include<queue>  
    #include<string.h>  
    #include<iostream>  
    #include<math.h>  
    #include<set>  
    #include<map>  
    #include<vector>  
    #include<iomanip>  
    using namespace std;  
    #define ll long long  
    #define pb push_back  
    #define FOR(a) for(int i=1;i<=a;i++)  
    const int inf=0x3f3f3f3f;  
    const int maxn=2e5+5e4+9;    
    const int mod=985003;
    
    int n;
    int root,sz,tot,head[mod+1];
    struct data1{int v,time,nxt;char ch[10];}hash[maxn];
    struct data2{int l,r,v,s,rnd,time;char ch[10];}tr[maxn];
    void update(int k){tr[k].s=tr[tr[k].l].s+tr[tr[k].r].s+1;}
    void rturn(int &k){int t=tr[k].l;tr[k].l=tr[t].r;tr[t].r=k;tr[t].s=tr[k].s;update(k);k=t;}
    void lturn(int &k){int t=tr[k].r;tr[k].r=tr[t].l;tr[t].l=k;tr[t].s=tr[k].s;update(k);k=t;}
    
    bool cmp(char a[],char b[]){for(int i=1;i<max(strlen(a),strlen(b));i++)if(a[i]!=b[i])return 0;return 1;}
    int Hash(char ch[]){
    	int s=0;
    	for(int i=1;i<strlen(ch);i++)
    	{s*=27;s+=(ch[i]-'A'+1);s%=mod;}
    	return s;
    }
    void del(int &k,int x,int time){
    	if(tr[k].v==x){
    		if(tr[k].time==time){
    			if(tr[k].l*tr[k].r==0)k=tr[k].l+tr[k].r;
    			else if(tr[tr[k].l].rnd<tr[tr[k].r].rnd){rturn(k);del(k,x,time);}
    			else {rturn(k);del(k,x,time);}
    		}
    		else if(time>tr[k].time){tr[k].s--;del(tr[k].l,x,time);}
    		else {tr[k].s--;del(tr[k].r,x,time);}
    	}
    	else if(x<tr[k].v){tr[k].s--;del(tr[k].l,x,time);}
    	else {tr[k].s--;del(tr[k].r,x,time);}
    }
    void insert(int &k,char ch[],int x,int time){			
    	if(k==0){
    		sz++;k=sz;tr[k].v=x;tr[k].s=1;tr[k].rnd=rand();
    		memcpy(tr[k].ch,ch,strlen(ch));tr[k].time=time;
    		return;
    	}
    	tr[k].s++;
    	if(x<=tr[k].v){insert(tr[k].l,ch,x,time);if(tr[tr[k].l].rnd<tr[k].rnd)rturn(k);}	
    	//小于等于都放在左儿子,所以时间大在左边
    	else{insert(tr[k].r,ch,x,time);if(tr[tr[k].r].rnd<tr[k].rnd)lturn(k);}
    }
    void INS(char ch[],int x,int time){		//hash[i]存储hash值为i的尾指针
    	int k=Hash(ch);int i=head[k];
    	while(i){
    		if(cmp(hash[i].ch,ch)){			//在冲突的哈希中检测同名,更新记录
    			del(root,hash[i].v,hash[i].time);
    			hash[i].time=time;hash[i].v=x;
    			insert(root,ch,x,time);
    			return;
    		}
    		i=hash[i].nxt;
    	}
    	tot++;								//给新的玩家分配一个节点
    	hash[tot].time=time;hash[tot].v=x;
    	memcpy(hash[tot].ch,ch,strlen(ch));
    	hash[tot].nxt=head[k];head[k]=tot;
    	insert(root,ch,x,time);
    }
    int get(char ch[]){						//获取字符串在hash[]数组中的下标
    	int k=Hash(ch);int i=head[k];
    	while(i){
    		if(cmp(hash[i].ch,ch))return i;
    		i=hash[i].nxt;
    	}
    }
    int getrank(int k,int x,int time){
    	if(k==0)return 0;
    	if(tr[k].v==x){				
    		if(tr[k].time>time)return getrank(tr[k].r,x,time);	
    		else if(tr[k].time<time)return 1+tr[tr[k].r].s+getrank(tr[k].l,x,time);	//先传记录优先
    		else return tr[tr[k].r].s+1;
    	}
    	else if(tr[k].v<x)return getrank(tr[k].r,x,time);
    	else return 1+tr[tr[k].r].s+getrank(tr[k].l,x,time);
    }
    void ask1(char ch[]){	//询问排名
    	int t=get(ch);
    	printf("%d
    ",getrank(root,hash[t].v,hash[t].time));
    }
    int index(int k,int x){	//获得第x名的树节点编号
    	if(tr[tr[k].r].s+1==x)return k;
    	else if(x<=tr[tr[k].r].s)return index(tr[k].r,x);
    	else return index(tr[k].l,x-tr[tr[k].r].s-1);
    }
    void ask2(char ch[]){
    	int s=0;
    	for(int i=1;i<strlen(ch);i++){s*=10;s+=ch[i]-'0';}
    	for(int i=s;i<=tot&&i<=s+9;i++){
    		printf("%s",tr[index(root,i)].ch+1);
    		if(i<tot&&i<s+9)printf(" ");
    	}
    	printf("
    ");
    }
    int main(){
    	scanf("%d",&n);char ch[11];int x;
    	for(int i=1;i<=n;i++){
    		scanf("%s",ch);
    		if(ch[0]=='+'){scanf("%d",&x);INS(ch,x,i);}
    		else if(ch[1]>='A'&&ch[1]<='Z')ask1(ch);
    		else ask2(ch);
    	}
    }


  • 相关阅读:
    (转)修改Android解锁界面
    linux terminal 快捷键
    (转)Android蓝牙开发浅析
    (转)android 编译单个模块
    (转)Android关机AppWidget的实现
    MyEclipse修改页面模板(JSP和HTML等) 分类: WEB项目应用 20100131 00:03 698人阅读 评论(1) 收藏
    定时任务:Timer类、TimerTask类 分类: java 20100317 22:01 551人阅读 评论(0) 收藏
    Socket读取输入流 分类: java 20100322 17:38 3330人阅读 评论(0) 收藏
    [Microsoft][SQLServer 2000 Driver for JDBC]Object has been closed. 分类: 开发常见问题解决方案 20100318 22:05 1106人阅读 评论(0) 收藏
    3/17/10 9:55:59 AM CST: [INFO] User settings file does not exist C:/Documents and Settings/Administrator/.m2/settings.xml 分类: 开发常见问题解决方案 20100317 10:20 3448人阅读 评论(4) 收藏
  • 原文地址:https://www.cnblogs.com/Drenight/p/8611214.html
Copyright © 2020-2023  润新知