线段树 区间合并

1 poj 3667

 题意:

支持两种操作 1 如果有连续长度大于D的房间,则输出最左的区间值, 否则输出0;2 将ql, qr区间的房间标记为             未入住

思路:节点维护三个域, 该节点的最大房间数,该节点左端点起的最大房间数, 该房间右端点起的最大连续房间数,用线段树进行更新和查询

#include 
   
   
    
    
#include 
    
    
     
     
using namespace std;
const int maxn = 50010;
typedef struct
{
  int s, l, r;
}node;
node a[maxn*4];
int col[maxn*4], ql, qr;
int n, m, t, v;
void construct(int o, int l, int r)
{
  a[o].s = a[o].l = a[o].r = r-l+1;
  col[o] = -1;
  if(l == r)  return;
  int m = (l+r) / 2;
  construct(2*o, l, m);
  construct(2*o+1, m+1, r);
}
void pushdown(int o, int l, int r)
{
  int m = (l+r) / 2;
  if(col[o] != -1)
   {
     a[2*o].s = a[2*o].l = a[2*o].r = col[o] ? 0 : m-l+1;
     a[2*o+1].s = a[2*o+1].l = a[2*o+1].r = col[o] ? 0: r-m;
     col[2*o] = col[2*o+1] = col[o];
     col[o] = -1;
   }
}
void pushup(int o, int l, int r)
{
  int m = (l+r) / 2;
  a[o].l = a[2*o].l + (a[2*o].l==m-l+1 ? a[2*o+1].l : 0);
  a[o].r = a[2*o+1].r + (a[2*o+1].r==r-m  ? a[2*o].r : 0);
  a[o].s = max(a[2*o].r+a[2*o+1].l, max(a[2*o].s, a[2*o+1].s));
  col[o] = -1;
}
int query(int o, int l, int r)
{
  if(a[o].l >= v)
  	return l;
  pushdown(o, l, r);
  int m = (l+r)/2;
  if(a[2*o].s >= v)  return query(2*o, l, m);
  if(a[2*o].r+a[2*o+1].l >= v)  return m-a[2*o].r+1;
  return query(2*o+1, m+1, r);
}
void update(int o, int l, int r)
{
  if(ql<=l &&qr>=r)
  	{
  	   col[o] = v;
       a[o].s = a[o].l = a[o].r = col[o] ? 0 : r-l+1;
       return;
  	}
  pushdown(o, l, r);
  int m = (l+r) / 2;
  if(ql <= m)   update(2*o, l, m);
  if(qr > m)    update(2*o+1, m+1, r);
  pushup(o, l, r);
}
int main()
{
  while(scanf("%d %d", &n, &m) == 2)
  	{
  	  construct(1, 1, n);
  	  while(m--)
  	  	{
  	  	  scanf("%d", &t);
  	  	  if(t == 1)
  	  	    {
  	  	      scanf("%d", &v);
  	  	      if(a[1].s < v)  puts("0");
  	  	      else
  	  	       {
  	  	       	 ql = query(1, 1, n);
  	  	       	 printf("%d\n", ql);
  	  	       	 qr = ql+v-1;
  	  	       	 v = 1;
  	  	       	 update(1, 1, n);
  	  	       }
  	  	    }
  	  	  else
  	  	    {
  	  	      scanf("%d %d", &ql, &v);
  	  	      qr = ql+v-1;
  	  	      v = 0;
  	  	      update(1, 1, n);
  	  	    }
  	  	}
  	}
  return 0;
}

    
    
   
   


2 hdu 3397

 和上一题差不多, 不多说

#include 
   
   
    
    
#include 
    
    
     
     
using namespace std;
const int maxn = 100010;
typedef struct 
{
  int s, l, r
}node;
node a[maxn*4];
int b[maxn], ql, qr;
int n, m, p, x, t;
char s[5];
void pushup(int o,int l, int r)
{ 
  int m = (l+r) / 2;
  a[o].l = a[2*o].l;
  if(a[o].l==m-l+1 && b[m+1]>b[m])
  	a[o].l += a[2*o+1].l;
  a[o].r = a[2*o+1].r;
  if(a[o].r==r-m && b[m+1]>b[m])
    a[o].r += a[2*o].r;
  a[o].s = max(a[2*o].s, a[2*o+1].s);
  if(b[m+1] > b[m])
  	a[o].s = max(a[o].s, a[2*o].r+a[2*o+1].l);
}
void construct(int o, int l, int r)
{
  if(l == r)
   {
   	 a[o].s = a[o].l = a[o].r = 1;
   	 return;
   }
  int m = (l+r) / 2;
  construct(2*o, l, m);
  construct(2*o+1, m+1, r);
  pushup(o, l, r);
}
void update(int o, int l, int r)
{
  if(l == r)
    {
      b[l] = x;
      return;
    }
  int m = (l+r) / 2;
  if(p <= m)
  	update(2*o, l, m);
  else
  	update(2*o+1, m+1, r);
  pushup(o, l, r);
}
int query(int o, int l, int r)
{
  if(ql<=l && qr>=r)
  	return a[o].s;
  int m = (l+r) / 2;
  int ans = 0;
  if(ql <= m)
  	ans = max(ans, query(2*o, l, m));
  if(qr > m)
  	ans = max(ans, query(2*o+1, m+1, r));
  if(ql<=m && qr>m && b[m+1]>b[m])
  	ans = max(ans, min(a[2*o].r, m-ql+1)+min(a[2*o+1].l, qr-m));
}
int main()
{
   scanf("%d", &t);
   while(t--)
   	 {
   	 	scanf("%d %d", &n, &m);
   	 	for(int i=1; i<=n; i++)
   	 	 scanf("%d", &b[i]);
   	 	construct(1, 1, n);
   	 	while(m--)
   	 	  {
   	 	  	scanf("%s", s);
   	 	  	if(s[0] == 'U')
   	 	  	  {
   	 	  	  	scanf("%d %d", &p, &x);
   	 	  	  	p++;
   	 	  	  	update(1, 1, n);
   	 	  	  }
   	 	  	else
   	 	  	  {
   	 	  	  	scanf("%d %d", &ql, &qr);
   	 	  	  	ql++, qr++;
   	 	  	  	printf("%d\n", query(1, 1, n));
   	 	  	  }
   	 	  }
   	 }
   return 0;
}

    
    
   
   

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值