线段树特殊查询
单点更新,查询左边第一满足条件的节点。
查询的时候类似于二分查找,查找的顺序是 整体--->左儿子--->右儿子 直到 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; }