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;

}

  

你可能感兴趣的:(ZOJ)