线段树特殊查询
单点更新,查询左边第一满足条件的节点。
查询的时候类似于二分查找,查找的顺序是 整体--->左儿子--->右儿子 直到 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 }
这道题比上一题难度上升很多,修改和查询都变成了针对区间的了。线段树的定义和查询方法也要做出相应的调整。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); } } } }
和上一道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;
}

浙公网安备 33010602011771号