线段树特殊查询

1.hdu2795 Billboard

单点更新,查询左边第一满足条件的节点。

查询的时候类似于二分查找,查找的顺序是 整体--->左儿子--->右儿子 直到 l=r 则找到了节点,判断的时候可以用tree[rt] ? v.

代码如下

 1 #include<bits/stdc++.h>
 2 #define rep(i,n) for(i=1;i<=n;i++)
 3 #define lson l,mid,rt<<1
 4 #define rson mid+1,r,rt<<1|1
 5 using namespace std;
 6 const int maxn=200100;
 7 int tree[maxn*4],w;
 8 void PushUp(int rt)
 9 {
10     tree[rt]=max(tree[rt<<1],tree[rt<<1|1]);
11 }
12 void build(int l,int r,int rt)
13 {
14     if(l==r)
15     {
16         tree[rt]=w;
17         return ;
18     }
19     int mid((l+r)>>1);
20     build(lson);
21     build(rson);
22     PushUp(rt);
23 }
24 void update(int p,int add,int l,int r,int rt)
25 {
26     if(l==r)
27     {
28         tree[rt]+=add;
29         return ;
30     }
31     int mid((l+r)>>1);
32     if(p<=mid)update(p,add,lson);
33     else update(p,add,rson);
34     PushUp(rt);
35 }
36 int query(int L,int R,int l,int r,int rt)
37 {
38     if(l>=L && r<=R)return tree[rt];
39     int mid((l+r)>>1);
40     if(mid>=R)return query(L,R,lson);
41     if(mid<L)return query(L,R,rson);
42     return max(query(L,R,lson),query(L,R,rson));
43 }
44 int find(int wi,int l,int r,int rt)
45 {
46     if(tree[rt]<wi)return -1; //itself? ---> leftson? ---> rightson?
47     if(l==r)return l;
48     int mid((l+r)>>1);
49     int u1=find(wi,lson);
50     if(u1!=-1)return u1;
51     int u2=find(wi,rson);
52     if(u2!=-1)return u2;
53     return -1;
54 }
55 int main()
56 {
57     int h,n;
58     while(scanf("%d%d%d\n",&h,&w,&n)!=EOF)
59     {
60         int i;
61         build(1,n,1);
62         int tot=min(n,h);
63         rep(i,n)
64         {
65             int wi;
66             scanf("%d",&wi);
67             int pos=find(wi,1,tot,1);
68             printf("%d\n",pos);
69             if(pos!=-1)update(pos,-wi,1,tot,1);
70         }
71     }
72 }

 2.poj3667 Hotel

  这道题比上一题难度上升很多,修改和查询都变成了针对区间的了。线段树的定义和查询方法也要做出相应的调整。op[rt]表示当前区间上最长的连续空区间的长度,lmax[rt]表示从左端开始最长的连续空区间的长度,rmax表示从右端开始最长的连续空区间的长度。更新的时候和GSS1的思路类似,先推出lmax和rmax,再通过这两者得到op。得到了这些,就可以查询满足条件的最左端的区间了。

   首先查询区间上的最长空区间的长度是多少,如果大于等于d,则说明这个区间上有答案,但答案具体是多少还不清楚。查询顺序是

op[rt]--->lmax[rt]---->find(lson)---->rmax[rt<<1]+lmax[rt<<1|1]---->find(rson)---->rmax[rt] ,按照这个顺序即可找出最左端满足条件的区间。

代码如下:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<cstring>
#define rep(i,n) for(i=1;i<=n;i++)
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define creatmid int mid=(l+r)>>1;
using namespace std;
const int maxn=50100;
int lmax[maxn*4],rmax[maxn*4],op[maxn*4],tag[maxn*4];
int n,m;
void PushUp(int l,int r,int rt)
{
    creatmid;
    lmax[rt]=lmax[rt<<1];rmax[rt]=rmax[rt<<1|1];
    if(lmax[rt]==mid-l+1)lmax[rt]+=lmax[rt<<1|1];
    if(rmax[rt]==r-mid)rmax[rt]+=rmax[rt<<1];
    op[rt]=max(max(op[rt<<1],op[rt<<1|1]),lmax[rt<<1|1]+rmax[rt<<1]);
}
void PushDown(int l,int r,int rt)
{
    //printf("l=%d r=%d rt=%d tag=%d\n",l,r,rt,tag[rt]);
    if(tag[rt]!=-1)
    {
        creatmid;
        lmax[rt<<1]=rmax[rt<<1]=op[rt<<1]=(mid-l+1)*tag[rt];
        lmax[rt<<1|1]=rmax[rt<<1|1]=op[rt<<1|1]=(r-mid)*tag[rt];
        tag[rt<<1]=tag[rt<<1|1]=tag[rt];
        tag[rt]=-1;
    }
}
void build(int l,int r,int rt)
{
    lmax[rt]=rmax[rt]=op[rt]=r-l+1;
    if(l==r)return ;
    creatmid;
    build(lson);
    build(rson);
}
int find(int l,int r,int rt,int d)
{
//    printf("l=%d r=%d rt=%d d=%d op=%d\n",l,r,rt,d,op[rt]);
    if(op[rt]<d)return 0;
    if(lmax[rt]>=d)return l;
    PushDown(l,r,rt);
    creatmid;
    int u1=find(l,mid,rt<<1,d);
    if(u1)return u1;
    if((lmax[rt<<1|1]+rmax[rt<<1])>=d)return mid-rmax[rt<<1]+1;
    int u2=find(mid+1,r,rt<<1|1,d);
    if(u2)return u2;
    if(rmax[rt]>=d)return r;
    return 0;
}
void update(int L,int R,int add,int l,int r,int rt)
{
    //printf("L=%d R=%d add=%d l=%d r=%d rt=%d\n",L,R,add,l,r,rt);
    if(l>=L && r<=R)
    {
        lmax[rt]=rmax[rt]=op[rt]=(r-l+1)*add;
        tag[rt]=add;
        return ;
    }
    PushDown(l,r,rt);
    creatmid;
    if(mid>=R)update(L,R,add,lson);
    else if(mid<L)update(L,R,add,rson);
    else
    {
        update(L,R,add,lson);
        update(L,R,add,rson);
    }
    PushUp(l,r,rt);
//    printf("L=%d R=%d add=%d l=%d r=%d rt=%d op=%d\n",L,R,add,l,r,rt,op[rt]);
}
int main()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        int i;
        memset(tag,-1,sizeof(tag));
        build(1,n,1);
    //    printf("%d %d %d\n",lmax[2],rmax[1],op[2]);
        rep(i,m)
        {
            int u;
            scanf("%d",&u);
            if(u==1)
            {
                int d;
                scanf("%d",&d);
                int p=find(1,n,1,d);
                printf("%d\n",p);
                if(p!=0) update(p,p+d-1,0,1,n,1);
            }
            else
            {
                int x,d;
                scanf("%d%d",&x,&d);
                int L=x,R=x+d-1;
            //    printf("L=%d R=%d\n",L,R);
                update(L,R,1,1,n,1);
            }
        }
    }
}

 3.hdu1540

和上一道hotel差不多,经验证,这里只需要维护lmax和rmax两个值就可以找出答案,而且这道题是单点修改,代码量不大,查找的顺序可以是这样

      lmax[rt](左边)--->rmax[rt<<1]+lmax[rt<<1|1](即中间)---->rmax[rt](右边)[前3个顺序可以任意调换]---->find(lson) or find(rson)

思路是当前区间找不到满足条件的就到左右儿子里面去找,当找到满足条件的或l==r时就停下来。

代码如下:

#include<bits/stdc++.h>
#define rep(i,n) for(i=1;i<=n;i++)
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define creatmid int mid=(l+r)>>1
using namespace std;
const int maxn=50100;
int stk[maxn*4];
int lmax[maxn*4],rmax[maxn*4];
int n,m;
void build(int l,int r,int rt)
{
	creatmid;
	lmax[rt]=rmax[rt]=r-l+1;
	if(l==r)return ;
	build(lson);
	build(rson);
}
void PushUp(int l,int r,int rt)
{
	creatmid;
	lmax[rt]=lmax[rt<<1];	rmax[rt]=rmax[rt<<1|1];
	if(lmax[rt]==mid-l+1)lmax[rt]+=lmax[rt<<1|1];
	if(rmax[rt]==r-mid)rmax[rt]+=rmax[rt<<1];
//	printf("l=%d r=%d rt=%d lmax=%d rmax=%d\n",l,r,rt,lmax[rt],rmax[rt]);
}
void update(int p,int add,int l,int r,int rt)
{
//	printf("p=%d add=%d l=%d r=%d rt=%d\n",p,add,l,r,rt);
	if(l==r)
	{
		lmax[rt]=rmax[rt]=add;
		return ;
	}
	creatmid;
	if(p<=mid)update(p,add,lson);
	else update(p,add,rson);
	PushUp(l,r,rt);
}
int find(int p,int l,int r,int rt)
{
//	printf("p=%d l=%d r=%d rt=%d\n",p,l,r,rt);
	if(l==r)return lmax[rt];
	//if(l==r)return lmax[rt];
	creatmid;
	int l1=lmax[rt];
//	printf("l1=%d\n",l1);
	if((l+l1-1)>=p)return l1;
//	printf("l1=%d\n",l1);
	int l2=lmax[rt<<1|1]+rmax[rt<<1];
//	printf("l2=%d lmax=%d rmax=%d\n",l2,lmax[rt<<1|1],rmax[rt<<1]);
	if((mid+lmax[rt<<1|1])>=p && (mid-rmax[rt<<1]+1<=p))return l2;
//	printf("l2=%d\n",l2);
	int l3=rmax[rt<<1|1];
	if((r-l3+1)<=p)return l3;
//	printf("l3=%d\n",l3);
	if(p<=mid) return find(p,lson);
	else return find(p,rson);
}
int main()
{
	while(scanf("%d%d\n",&n,&m)!=EOF)
	{
		//while(!que.empty())que.pop();
		memset(stk,0,sizeof(stk));
		build(1,n,1);
		int i,pre=0,top=0;char c;
		rep(i,m)
		{
			int u;
			scanf("%c ",&c);
			if(c=='D')
			{
				scanf("%d\n",&u);
				stk[++top]=u;
				update(u,0,1,n,1);
			}
			else if(c=='R')
				 {
				 	if(top>0)
					{	
					 	pre=stk[top];
	 				 	stk[top--]=0;
	 				 	if(pre>0)
	 						update(pre,1,1,n,1);
					}
				}
				else
				{
					scanf("%d\n",&u);
					printf("%d\n",find(u,1,n,1));
				}
		}
	}
	return 0;
}

  还有另一版本,自我感觉这个比较鸡肋。

#include<bits/stdc++.h>
#define rep(i,n) for(i=1;i<=n;i++)
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define creatmid int mid=(l+r)>>1
using namespace std;
const int maxn=50100;
stack<int>sta;
int lmax[maxn*4],rmax[maxn*4],op[maxn*4];
int n,m;
void build(int l,int r,int rt)
{
	lmax[rt]=rmax[rt]=op[rt]=r-l+1;
	if(l==r)return ;
	creatmid;
	build(lson);
	build(rson);
}
void PushUp(int l,int r,int rt)
{
	lmax[rt]=lmax[rt<<1];  rmax[rt]=rmax[rt<<1|1];
	creatmid;
	if(lmax[rt]==mid-l+1)lmax[rt]+=lmax[rt<<1|1];
	if(rmax[rt]==r-mid)rmax[rt]+=rmax[rt<<1];
	op[rt]=max(max(op[rt<<1],op[rt<<1|1]),lmax[rt<<1|1]+rmax[rt<<1]);
}
void update(int p,int add,int l,int r,int rt)
{
	if(l==r)
	{
		lmax[rt]=rmax[rt]=op[rt]=add;
		return ;
	}
	creatmid;
	if(p<=mid)update(p,add,lson);
	else update(p,add,rson);
	PushUp(l,r,rt);
}
int find(int p,int l,int r,int rt)
{
	if(op[rt]==0)return 0;
	if(l==r)return lmax[rt];
	creatmid;
	if(p<=mid)
	{
		if(mid-rmax[rt<<1]+1<=p)return rmax[rt<<1]+lmax[rt<<1|1];
		return find(p,lson);
	}
	else
	{
		if(mid+lmax[rt<<1|1]>=p)return lmax[rt<<1|1]+rmax[rt<<1];
		return find(p,rson);
	}
}
int main()
{
	while(scanf("%d%d",&n,&m)!=EOF)
	{
		while(!sta.empty())sta.pop();
		build(1,n,1);
		int i,p; char c[5];
		rep(i,m)
		{
			scanf("%s",&c);
			if(c[0]=='D')
			{
				scanf("%d",&p);
				sta.push(p);
				update(p,0,1,n,1);
			}
			else if(c[0]=='Q')
			{
				scanf("%d",&p);
				printf("%d\n",find(p,1,n,1));
			}
			else
			{
				if(sta.empty())continue;
				int u=sta.top();
				sta.pop();
				update(u,1,1,n,1);
			}
		}
	}
	return 0;
}

  

posted @ 2015-11-29 21:29  UESTC-Ulysses  阅读(229)  评论(0编辑  收藏  举报