hdu 1540 线段树区间合并

来源:互联网 发布:死去元知万事空的意思 编辑:程序博客网 时间:2024/05/20 21:46

线段树区间合并~第一次接触,

解决这道题,说下思路,(1)创建树节点,每个节点要记录左连续个数和右连续个数,同时还要有一个标记量cover,当cover为1时,这个区间内所有点都是好的,当cover为0的时候说明这个区间内有一些点被破坏了;

(2)比如要你找出与 x 直接或者间接相连的点的个数,那么我们可以找出区间为(1,x-1)的节点,那么它的左连续个数可以知道,同理找到区间为(x+1,n)的节点,那么他的右连续个数也可以知道,最后再加上1,因为自己本身也得包含进去。

附上代码:

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <stack>
#define N 55000
using namespace std;
struct node
{
 int l,r;
 int lenl,lenr,cover;   
}st[N*5];
int rec[N];
void build(int v,int l,int r)

  st[v].l=l;
  st[v].r=r;
  st[v].lenl=st[v].lenr=(r-l+1);
  st[v].cover=1;
  if(l==r)return;
  int mid=(l+r)/2;
  build(2*v,l,mid);
  build(2*v+1,mid+1,r);

void update(int v,int w,int val)
{
 if(st[v].l==st[v].r)
 {
   st[v].lenl=st[v].lenr=val;
   st[v].cover=val;
   return;
 }
 if(st[v].cover)
 {
   st[v*2].cover=st[v].cover;
   st[v*2+1].cover=st[v].cover;
   st[v].cover=0;   
 }
 int mid=(st[v].l+st[v].r)/2;
 if(w<=mid)
       update(2*v,w,val);
 else if(w>mid)
       update(2*v+1,w,val);
 st[v].lenl=st[2*v].lenl;
 st[v].lenr=st[2*v+1].lenr;
 if(st[2*v].cover==1)
    st[v].lenl+=st[v*2+1].lenl;
 if(st[2*v+1].cover==1)
    st[v].lenr+=st[v*2].lenr;
 st[v].cover=st[v*2].cover&&st[v*2+1].cover;
}
int lquery(int v,int l,int r)
{
  if(st[v].l==l&&st[v].r==r)
  {
    return st[v].lenl;
  }
  int mid=(st[v].l+st[v].r)/2;
  if(r<=mid)
     return lquery(2*v,l,r);
  else if(l>mid)
     return lquery(2*v+1,l,r);
  else
    {
      int t=lquery(2*v,l,mid);
      if(t==mid-l+1)
      {
        t+=lquery(2*v+1,mid+1,r);   
      }        
      return t;
    }
}
int rquery(int v,int l,int r)
{
  if(st[v].l==l&&st[v].r==r)
  {
    return st[v].lenr;
  }
  int mid=(st[v].l+st[v].r)/2;
  if(r<=mid)
     return rquery(2*v,l,r);
  else if(l>mid)
     return rquery(2*v+1,l,r);
  else
    {
      int t=rquery(2*v+1,mid+1,r);
      if(t==r-mid)
      {
        t+=rquery(2*v,l,mid);   
      }        
      return t;
    }
}
int main()
{
 int n,m;
 while(scanf("%d%d",&n,&m)!=EOF)
 {
   stack<int>stk;
   memset(rec,0,sizeof(rec));
   int cnt=0;
   char s[10];
   build(1,1,n);
   for(int i=0;i<m;i++)
   {
    scanf("%s",s);
    if(s[0]=='D')
    {
     int a;
     scanf("%d",&a);
     rec[a]=1;
     stk.push(a);
     update(1,a,0);
    }
    else if(s[0]=='R')
    {
      if(!stk.empty())
      {
        int a=stk.top();
        rec[a]=0;
        stk.pop();
        update(1,a,1);  
      }
    }
    else if(s[0]=='Q')
    {
       int a;
       scanf("%d",&a);
       if(rec[a])
        printf("0\n");
       else
        {
          if(a==1)                                                     //我的代码得分三种情况,当询问第一个点的时候,当询问最后一个点的时候,当所询问点在中间的时候,就因为这个地方没注意,                                                                                //  RE了很多次

            printf("%d\n",lquery(1,2,n)+1);
          else if(a==n)
            printf("%d\n",rquery(1,1,n-1)+1);
          else
          printf("%d\n",lquery(1,a+1,n)+rquery(1,1,a-1)+1);
        }
    }
   }
  }
 return 0;   
}


0 0