LG-P1503 鬼子进村

P1503 鬼子进村
题目链接
题目背景

小卡正在新家的客厅中看电视。电视里正在播放放了千八百次依旧重播的《亮剑》,剧中李云龙带领的独立团在一个县城遇到了一个鬼子小队,于是独立团与鬼子展开游击战。

题目描述

描述 县城里有n个用地道相连的房子,第i个只与第i-1和第i+1个相连。这是有m个消息依次传来

1、消息为D x:鬼子将x号房子摧毁了,地道被堵上。

2、消息为R :村民们将鬼子上一个摧毁的房子修复了。

3、消息为Q x:有一名士兵被围堵在x号房子中。

李云龙收到信息很紧张,他想知道每一个被围堵的士兵能够到达的房子有几个。

输入格式
第一行2个整数n,m(n,m=50000)。

接下来m行,有如题目所说的三种信息共m条。

输出格式
对于每一个被围堵的士兵,输出该士兵能够到达的房子数。

输入样例
7 9
D 3
D 6
D 5
Q 4
Q 5
R
Q 4
R
Q 4
输出样例
1
0
2
4
说明

若士兵被围堵在摧毁了的房子中,那只能等死了。。。。。。

题解
小题是多解的,以至于暴力好像都可以解(洛谷博客中有一位网友声称自己的暴力过了)。

我首先想到的就是分块,记录每个块中最左边和最右边被拆掉的房子(记作ansL和ansR)。
添加的时候,顺便修正这块的ansL和ansR。O(1)
删除的时候,也要修正这块的ansL和ansR。O(k) 其中k为每块的点数。
查询的时候,先看看查询的点所在的块中有没有被拆的,如果没有,那么就看看左边和右边的块里分别有没有 ansR 和 ansL(详见代码)

后来发现还可以用平衡树来做,把拆掉的点加入树中,查询的时候,查找前驱和后继,删除就直接删除。注意,要提前塞入一个 0 和一个 n+1。

代码
分块

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define pd(ch) ch!='R'&&ch!='Q'&&ch!='D'
using namespace std;
const int maxn=5e4+5,maxt=5e2+5;
int n,m,q,tot,id[maxn],L[maxt],R[maxt],ansL[maxt],ansR[maxt],st[maxn];
int vis[maxn];
//id每个点所在组号,L每组左边界,R每组右边界
//vis每个点的状态,ansL和ansR表示每组最左边第一个和最右边第一个拆了的点
void ins(int x)
{
    if (vis[x]) return;
    vis[x]=1;st[++st[0]]=x;
    int y=id[x];
    if (ansL[y]==-1||ansL[y]>x) ansL[y]=x;
    if (ansR[y]<x) ansR[y]=x;
}
void del(int x)
{
    if (!vis[x]) return;
    vis[x]=0;int y=id[x],i;
    if (ansL[y]==x)
      for (i=L[y],ansL[y]=-1;i<=R[y];i++)
        if (vis[i]) {ansL[y]=i;break;}
    if (ansR[y]==x)
      for (i=R[y],ansR[y]=-1;i>=L[y];i--)
        if (vis[i]) {ansR[y]=i;break;}
}
int fin(int x)
{
    pair<int,int>ans;
    ans.first=0,ans.second=n+1;
    int y=id[x];
    if (ansL[y]!=-1&&ansL[y]<=x)
    {
        for (int i=x;i>=L[y];i--)
          if (vis[i]) {ans.first=i;break;}
    }else
    {
        for (int i=y-1;i>=1;i--)
          if (ansR[i]!=-1) {ans.first=ansR[i];break;}
    }
    if (ansR[y]!=-1&&ansR[y]>=x)
    {
        for (int i=x;i<=R[y];i++)
          if (vis[i]) {ans.second=i;break;}
    }else
    {
        for (int i=y+1;i<=tot;i++)
          if (ansL[i]!=-1) {ans.second=ansL[i];break;}
    }
    return max(0,ans.second-ans.first-1);
}
int main()
{
    scanf("%d%d",&n,&q);
    m=sqrt(n);
    for (int i=1;i<=n;)
    {
        tot++;ansL[tot]=-1;ansR[tot]=-1;
        L[tot]=i;R[tot]=min(i+m-1,n);
        for (;i<=R[tot];i++) id[i]=tot;
    }
    for (int i=1,x;i<=q;i++)
    {
        char ch=getchar();
        while (pd(ch)) ch=getchar();
        if (ch!='R') scanf("%d",&x);
        if (ch=='R') {if (st[0]>0) del(st[st[0]--]);}else
        if (ch=='Q') printf("%d\n",fin(x));else
        if (ch=='D') ins(x);
    }
    return 0;
}

Treap

#include<ctime>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define rd() ((rand()|rand()<<15)^(rand()|rand()<<15))
#define pd(ch) (ch!='D'&&ch!='Q'&&ch!='R')
#define INF 100000000
using namespace std;
const int maxn=5e4+5;
int n,m,st[maxn];
bool vis[maxn];
struct js{
    int x,r;
    js* son[2];
    js(){son[0]=son[1]=NULL;r=rd();}
};
js *rot=NULL;
void rotate(js* &o,int p)//用son[p]来代替当前节点
{
    js *u=o->son[p];
    o->son[p]=u->son[p^1];
    u->son[p^1]=o;
    o=u;
}
void insert(js* &o,int d)
{
    if (o==NULL) {o=new js();o->x=d;}
    if (o->x==d) return;
    int p=o->x<d;
    insert(o->son[p],d);
    if (o->son[p]->r>o->r) rotate(o,p);
}
int qia(js* &o,int d)
{
    if (o==NULL) return -INF;
    return o->x>d?qia(o->son[0],d):max(o->x,qia(o->son[1],d));
}
int hou(js* &o,int d)
{
    if (o==NULL) return INF;
    return o->x<d?hou(o->son[1],d):min(o->x,hou(o->son[0],d));
}
void remov(js* &o,int d)
{
    int k=(o->son[0]!=NULL)+(o->son[1]!=NULL);
    if (k==2)
    {
        rotate(o,o->son[0]->r<o->son[1]->r);
        if (o->son[0]!=NULL&&o->son[0]->x==d) remov(o->son[0],d);
        else remov(o->son[1],d);
    }else if (k==0) o=NULL;else
    {
        rotate(o,o->son[1]!=NULL);
        if (o->son[0]!=NULL&&o->son[0]->x==d) remov(o->son[0],d);
        else remov(o->son[1],d);
    }
}
void delet(js* &o,int d)
{
    if (o->x==d) {remov(o,d);return;}
    int p=o->x<d;
    delet(o->son[p],d);
}
int main()
{
    srand((int)time(NULL));
    scanf("%d%d",&n,&m);
    insert(rot,0);insert(rot,n+1);
    for (int i=1,x;i<=m;i++)
    {
        char ch=getchar();
        while (pd(ch)) ch=getchar();
        if (ch!='R') scanf("%d",&x);
        if (ch=='R') {if (st[0]>0&&vis[x=st[st[0]]]) delet(rot,x),vis[x]=0,st[0]--;}else
        if (ch=='Q') printf("%d\n",max(0,hou(rot,x)-qia(rot,x)-1));else
        {if (!vis[x]) insert(rot,x),vis[x]=1;st[++st[0]]=x;}
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/xu0_zy/article/details/80626263