codeforces 178C3 - Smart Beaver and Resolving Conflicts 线段树

 

      题目大意:这道题用到了hash表处理冲突的一种办法,给你一个大小为h的hash表标号从0到h-1,记为hash[0]~hash[h-1]

有两种操作:

1:"+ id ha":表示向哈希表中插入一个 哈希值为h,标号为id的元素,若hash[ha]为空,则直接插入即可,若hash[ha]已被占据,则给一个数m,在(ha+m)%h处插入,若还为非空,则继续在(ha+2*m)%h处插入,直到找到一个位置插入。(题目保证不会出现无法插入的情况)若最后插入的位置为(ha+i*m)%h,则需要耗费i点代价。

2.  "- id":表示删除一个标号为id的元素.(保证id在哈希表里)。

现在给出n个操作,问最后所付出的代价为多少。

      思路:我们观察可以发现,对于每一个位置,若出现冲突,它的下一个位置是确定的,事实上,它们共同构成一个回路,则我们可以将这个回路变成一条链放到线段树中,线段树实现两种操作,一种是将一个位置填满(赋值为1)或清空(赋值为0),二是返回一个区间中最靠左的空位置的在线段树中的位置,若没有则返回-1.因为一个哈希表中可能存在多条链,我们首先要维护每个位置在那条链上,每条链在线段数中的左右顶点是多少,还有每个位置在线段树中的位置,这可以在预处理中完成,这样一来,对于操作二,直接找到标号id之前插入的位置(我用map实现的),将该位置清空即可,对于操作一,设给你的哈希值为ha,则找到ha在线段树中对应的位置po,和ha所在区间的左右点l,r,先返回[po,r]的最左边的空余位置,若没有,再返回[l,po]的最左边的空余位置。设最后插入的位置为pp,则id所插入的位置为pp(在线段树中)。剩下的就是求代价了,有了pp,po,l,r,这很好求吧,具体实现看代码吧。

#include <iostream>
#include <string.h>
#include <stdio.h>
#include <map>
#define maxn 200010
#define mid ((t[p].l+t[p].r)>>1)
#define ls (p<<1)
#define rs (ls|1)
using namespace std;
map<int,int> mp;
struct tree
{
    int l,r;
    int po;
}t[maxn<<1];
void pushup(int p)
{
    if(t[ls].po!=-1)
    t[p].po=t[ls].po;
    else if(t[rs].po!=-1)
    t[p].po=t[rs].po;
    else
    t[p].po=-1;
}
void build(int p,int l,int r)
{
    t[p].l=l,t[p].r=r;
    if(l==r)
    {
        t[p].po=l;
        return;
    }
    build(ls,l,mid);
    build(rs,mid+1,r);
    pushup(p);
}
void change(int p,int x,int val)
{
    if(t[p].l==t[p].r)
    {
        if(val)
        {
            t[p].po=-1;
        }
        else
        {
            t[p].po=t[p].l;
        }
        return;
    }
    if(x>mid)
    change(rs,x,val);
    else
    change(ls,x,val);
    pushup(p);
}
int getpo(int p,int l,int r)
{
    if(t[p].l==l&&t[p].r==r)
    {
        return t[p].po;
    }
    if(r<=mid)
    return getpo(ls,l,r);
    else if(l>mid)
    return getpo(rs,l,r);
    else
    {
        int ll=getpo(ls,l,mid),rr=getpo(rs,mid+1,r);
        if(ll!=-1)
        return ll;
        if(rr!=-1)
        return rr;
        return -1;

    }
}
int po[maxn],vis[maxn],lr[maxn][2];
void init(int n,int m)
{
    int i,tmp,num=1,sum=1;
    lr[0][0]=lr[0][1]=0;
    for(i=0;i<n;i++)
    {
        if(vis[i])
        continue;
        tmp=i;
        lr[sum][0]=num;
        while(!vis[tmp])
        {
            po[tmp]=num++;
            vis[tmp]=sum;
            tmp=(tmp+m)%n;
        }
        lr[sum][1]=num-1;
        sum++;
    }
}
int main()
{
    freopen("dd.txt","r",stdin);
    int h,m,n,a,b;
    scanf("%d%d%d",&h,&m,&n);
    init(h,m);
    build(1,1,h);
    char str[2];
    long long ans=0;
    while(n--)
    {
        scanf("%s",str);
        if(str[0]=='+')
        {
            scanf("%d%d",&a,&b);
            int num=vis[b];//b在第num个区间
            int l=lr[num][0],r=lr[num][1];
            int p=po[b];
            int pp=getpo(1,p,r);
            if(pp!=-1)
            {
                ans+=(pp-p);
            }
            else
            {
                ans+=r-p;
                pp=getpo(1,l,p);
                ans+=pp-l+1;
            }
            change(1,pp,1);
            mp.insert(make_pair(a,pp));
        }
        else
        {
            scanf("%d",&a);
            int p=mp.find(a)->second;
            change(1,p,0);
            mp.erase(a);
        }
    }
    printf("%I64d\n",ans);
    return 0;
}


 

 

 

你可能感兴趣的:(codeforces 178C3 - Smart Beaver and Resolving Conflicts 线段树)