BZOJ 1826: [JSOI2010]缓存交换

题目:http://www.lydsy.com/JudgeOnline/problem.php?id=1826 

分析:

  贪心+堆或者平衡树(以下统一称为树)。越在后面,切换他是最好的。。。

  1.当已经在树上的时候,换掉之前已在树上的该主存块,换成当前主存块的下一个出现的位置。
  2.当前可用的cache足够的时候,直接插入到树中。
  3.每次需要切换cache的时候,都切掉距离当前位置最远的那个主存块,然后将当前的cache的下一次出现的位置更新到树上。

  先离散化,然后使用池子法从后往前扫,这样就可以统计每个主存块下一次出现的位置,插入的时候,直接插入的是当前主存块的下一个他出现的位置

329452 yejinru 1826 Accepted 7048 kb 404 ms C++/Edit 4397 B 2012-12-16 10:32:33

 

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <map>

using namespace std;

const int X = 100005;

#define debug puts("here");

int tot;

struct node{
    int l,r,s,val;
    void init(int _val){
        l = r = 0;
        s = 1;
        val = _val;
    }
}sbt[X];

void left_rotate(int &t){
    int k = sbt[t].r;
    sbt[t].r = sbt[k].l;
    sbt[k].l = t;
    sbt[k].s = sbt[t].s;
    sbt[t].s = sbt[sbt[t].l].s+sbt[sbt[t].r].s+1;
    t = k;
}

void right_rotate(int &t){
    int k = sbt[t].l;
    sbt[t].l = sbt[k].r;
    sbt[k].r = t;
    sbt[k].s = sbt[t].s;
    sbt[t].s = sbt[sbt[t].l].s+sbt[sbt[t].r].s+1;
    t = k;
}

void maintain(int &t,bool ok){
    if(!ok){
        if(sbt[sbt[sbt[t].l].l].s>sbt[sbt[t].r].s)
            right_rotate(t);
        else if(sbt[sbt[sbt[t].l].r].s>sbt[sbt[t].l].s){
            left_rotate(sbt[t].l);
            right_rotate(t);
        }
        else return;
    }
    else{
        if(sbt[sbt[sbt[t].r].r].s>sbt[sbt[t].l].s)
            left_rotate(t);
        else if(sbt[sbt[sbt[t].r].l].s>sbt[sbt[t].l].s){
            right_rotate(sbt[t].r);
            left_rotate(t);
        }
        else return;
    }
    maintain(sbt[t].l,0);
    maintain(sbt[t].r,1);
    maintain(t,0);
    maintain(t,1);
}

void insert(int &t,int val){
    if(!t){
        t = ++tot;
        sbt[t].init(val);
        return;
    }
    sbt[t].s++;
    if(val<sbt[t].val)
        insert(sbt[t].l,val);
    else
        insert(sbt[t].r,val);
    maintain(t,val>=sbt[t].val);
}

int del(int &t,int val){
    if(!t)  return 0;
    sbt[t].s--;
    if(val==sbt[t].val||(val<sbt[t].val&&!sbt[t].l)||(val>sbt[t].val&&!sbt[t].r)){
        if(sbt[t].l&&sbt[t].r){
            int pos = del(sbt[t].l,val+1);
            sbt[t].val = sbt[pos].val;
            return pos;
        }
        else{
            int pos = t;
            t = sbt[t].l+sbt[t].r;
            return pos;
        }
    }
    return del(val<sbt[t].val?sbt[t].l:sbt[t].r,val);
}

int find_max(int t){
	while(sbt[t].r)
		t = sbt[t].r;
	return sbt[t].val;
}

int find(int t,int val){
	if(!t)
		return 0;
	if(sbt[t].val==val)
		return true;
	if(sbt[t].val>val)
		return find(sbt[t].l,val);
	return find(sbt[t].r,val);
}

int a[X],n;
map<int,int> ma;
int po[X],tol,Next[X];

int main(){
	int n,m;
	int inf = 100000000;
	while(cin>>n>>m){
		tot = 0;
		ma.clear();

		int cnt = 0;
		int x,y;
		int root = 0;
		tol = n;

		for(int i=1;i<=n;i++){
			scanf("%d",&a[i]);
			if(ma[a[i]]==0)	//使用map离散化
				ma[a[i]] = ++cnt;
			po[i] = ++tol;
		}

		for(int i=n;i;i--){
			x = ma[a[i]];
			Next[i] = po[x];	//池子法,从后往前扫
			po[x] = i;
		}

		cnt = 0;
		int ans = 0;
		for(int i=1;i<=n;i++){
			if(find(root,i)){	//已存在树中,直接删除后更新
				del(root,i);
				insert(root,Next[i]);
			}
			else{
				ans ++;
				if(cnt==m)		//cache数不够了,需要删除
					del(root,find_max(root));
				else			//够用的话,但是需要插入,cache已使用的数目加一
					cnt ++;
				insert(root,Next[i]);//插入当前主存块的下一个位置
			}
		}
			
		cout<<ans<<endl;
	}
	return 0;
}

  

posted @ 2012-12-16 12:44  yejinru  阅读(368)  评论(0编辑  收藏  举报