Hotel
题意:
一开始旅馆有1~n间空房间,陆陆续续来了一些旅游团。每个个旅游团想租到d间连续的房间,否则他们不租,且房间号尽量靠前。旅游团每次退掉从x开始的d间房间,退掉的房子又是空的了。
输入:
n房间数,q操作数。1表示租房 d表示连续的房间数;2表示退房,x开始号,d退房数。
输出:
每次租房时,输出被租出的第一个房间号。
解析:
合并时L,R,len,lazy维护;
L代表左起最长 R代表右起最长 len代表区间最长 ;
(注意这种题,lazy的初始值设置为-1!)
合并区间时,len等于子区间len与左右子R,L之和的最大值;当左儿子区间满时,L等于左儿子区间加上右儿子L之和;当右儿子区间为满时R等于右儿子区间加上左儿子R之和。
然后这道题的重点是查询,就是最左边连续1长为d(或大于)的位置。num为要查询的长度, 当左儿子区间最长大于num,就去左儿子找,否则如果中间满足长度,可以直接退出长度,最后去右边找
int query(int rt,int l,int r,int need){
if(len[rt]==r-l+1) return l;
int m=(l+r)>>1;
push_down(rt,l,r);
if(len[rt<<1]>=need)
query(rt<<1,l,m,need);
else if(R[rt<<1]+L[rt<<1|1]>=need)
return m-R[rt<<1]+1;
else if(len[rt<<1|1]>=need)
return query(rt<<1|1,m+1,r,need);
}
ac代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<bitset>
using namespace std;
typedef long long ll;
const int maxn=5e4+10;
int n,m;
int len[maxn<<2],L[maxn<<2],R[maxn<<2],lazy[maxn<<2];
void build(int rt,int l,int r){
len[rt]=L[rt]=R[rt]=r-l+1;
lazy[rt]=-1;
if(l==r) return ;
int m=(l+r)>>1;
build(rt<<1,l,m);
build(rt<<1|1,m+1,r);
}
void push_up(int rt,int l,int r){
int m=(l+r)>>1;
len[rt]=max(len[rt<<1],len[rt<<1|1]);
len[rt]=max(len[rt],R[rt<<1]+L[rt<<1|1]);
L[rt]=L[rt<<1];
if(m-l+1==L[rt<<1]){
L[rt]+=L[rt<<1|1];
}
R[rt]=R[rt<<1|1];
if(r-m==R[rt<<1|1]){
R[rt]+=R[rt<<1];
}
}
void push_down(int rt,int l,int r){
if(lazy[rt]!=-1){
int m=(l+r)>>1,v=lazy[rt];
len[rt<<1]=R[rt<<1]=L[rt<<1]=v?0:m-l+1;
len[rt<<1|1]=R[rt<<1|1]=L[rt<<1|1]=v?0:r-m;
lazy[rt<<1]=lazy[rt<<1|1]=v;
lazy[rt]=-1;
}
}
void update(int rt,int l,int r,int ll,int rr,int v){
if(ll<=l&&r<=rr){
len[rt]=R[rt]=L[rt]=v?0:r-l+1;
lazy[rt]=v;
return ;
}
push_down(rt,l,r);
int m=(l+r)>>1;
if(ll<=m) update(rt<<1,l,m,ll,rr,v);
if(m<rr) update(rt<<1|1,m+1,r,ll,rr,v);
push_up(rt,l,r);
}
int query(int rt,int l,int r,int need){
if(len[rt]==r-l+1) return l;
int m=(l+r)>>1;
push_down(rt,l,r);
if(len[rt<<1]>=need)
query(rt<<1,l,m,need);
else if(R[rt<<1]+L[rt<<1|1]>=need)
return m-R[rt<<1]+1;
else if(len[rt<<1|1]>=need)
return query(rt<<1|1,m+1,r,need);
}
int main(){
while(~scanf("%d%d",&n,&m)){
build(1,1,n);
int op;
while(m--){
scanf("%d",&op);
if(op==1){
int l;
scanf("%d",&l);
if(len[1]<l)puts("0");//本店最大的间
else{
int start=query(1,1,n,l);
printf("%d\n",start);
update(1,1,n,start,start+l-1,1);
}
}
else if(op==2){
int start,l;
scanf("%d%d",&start,&l);
update(1,1,n,start,start+l-1,0);
}
}
}
return 0;
}
Tunnel Warfare
题意:
1~n个村庄,q次操作。Dx表示炸毁第x个村庄,Qx表示x包含x的完好连续村庄数,R表示恢复上一次炸毁的村庄。
解析
重点查询:当pos左儿子的R或右儿子的L里可直接得到长度 否则再去左右儿子中找。另外因为这查询结果可能是0,所以只有l==r是返回
int query(int rt,int l,int r,int pos){
if(l==r) return len[rt];
int m=(l+r)>>1;
if(pos<=m) {
if(pos+R[rt<<1]>m)
return R[rt<<1]+L[rt<<1|1];
else
return query(rt<<1,l,m,pos);
}
if(pos>m){
if(pos-L[rt<<1|1]<=m)
return R[rt<<1]+L[rt<<1|1];
else
return query(rt<<1|1,m+1,r,pos);
}
}
ac代码
#include<bits/stdc++.h>
using namespace std;
const int maxn=5e5+10;
int len[maxn<<2],L[maxn<<2],R[maxn<<2],lazy[maxn<<2];
char opt[20];
int a[maxn];
void push_up(int rt,int l,int r){
len[rt]=max(len[rt<<1],len[rt<<1|1]);
len[rt]=max(len[rt],R[rt<<1]+L[rt<<1|1]);
int m=(l+r)>>1,ll=m-l+1,rr=r-m;
L[rt]=L[rt<<1];
if(L[rt<<1]==ll){
L[rt]+=L[rt<<1|1];
}
R[rt]=R[rt<<1|1];
if(R[rt<<1|1]==rr){
R[rt]+=R[rt<<1];
}
}
void build(int rt,int l,int r){
len[rt]=L[rt]=R[rt]=r-l+1;
a[l]=1;
if(l==r) return ;
int m=(l+r)>>1;
build(rt<<1,l,m);
build(rt<<1|1,m+1,r);
}
void update(int rt,int l,int r,int pos,int v){
if(l==r){
len[rt]=L[rt]=R[rt]=v;
return ;
}
int m=(l+r)>>1;
if(pos<=m) update(rt<<1,l,m,pos,v);
if(pos>m) update(rt<<1|1,m+1,r,pos,v);
push_up(rt,l,r);
}
int query(int rt,int l,int r,int pos){
if(l==r) return len[rt];
int m=(l+r)>>1;
if(pos<=m) {
if(pos+R[rt<<1]>m) return R[rt<<1]+L[rt<<1|1];
else return query(rt<<1,l,m,pos);
}
if(pos>m){
if(pos-L[rt<<1|1]<=m) return R[rt<<1]+L[rt<<1|1];
else return query(rt<<1|1,m+1,r,pos);
}
}
int main(){
int n,m;
while(scanf("%d%d",&n,&m)!=EOF){
build(1,1,n);
stack<int> sk;
while(m--){
scanf("%s",&opt);
if(opt[0]=='D'){
int x;
scanf("%d",&x);
update(1,1,n,x,0);
sk.push(x);
}
if(opt[0]=='Q'){
int x;
scanf("%d",&x);
printf("%d\n",query(1,1,n,x));
}
if(opt[0]=='R'){
int x=sk.top();
sk.pop();
update(1,1,n,x,1);
}
}
}
return 0;
}
Black And White
题意
区间异或求区间内最长1串的长度
解析
关于查询:
如果查询区间完全在左右儿子,则直接去查;否则结果就是左右儿子所覆盖的查询长度和中间长度(主要求法)的最大值
int query(int rt,int l,int r,int ll,int rr){
if(ll<=l&&r<=rr){
return len1[rt];
}
push_down(rt,l,r);
int m=(l+r)>>1;
if(rr<=m) return query(rt<<1,l,m,ll,rr);
if(ll>m) return query(rt<<1|1,m+1,r,ll,rr);
int ls=query(rt<<1,l,m,ll,rr);
int rs=query(rt<<1|1,m+1,r,ll,rr);
int lll=R1[rt<<1];
if(lll>m-ll+1) lll=m-ll+1;
int rrr=L1[rt<<1|1];
if(rrr>rr-(m+1)+1) rrr=rr-(m+1)+1;
return max(max(ls,rs),lll+rrr);
// return res;
}
ac代码
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+10;
int a[maxn],len0[maxn<<2],L0[maxn<<2],R0[maxn<<2],len1[maxn<<2],L1[maxn<<2],R1[maxn<<2],lazy[maxn<<2];
void push_up(int rt,int l,int r){
len0[rt]=max(len0[rt<<1],len0[rt<<1|1]);
len0[rt]=max(len0[rt],R0[rt<<1]+L0[rt<<1|1]);
len1[rt]=max(len1[rt<<1],len1[rt<<1|1]);
len1[rt]=max(len1[rt],R1[rt<<1]+L1[rt<<1|1]);
int m=(l+r)>>1,ll=m-l+1,rr=r-m;
L0[rt]=L0[rt<<1];
if(len0[rt<<1]==ll){
L0[rt]+=L0[rt<<1|1];
}
R0[rt]=R0[rt<<1|1];
if(len0[rt<<1|1]==rr){
R0[rt]+=R0[rt<<1];
}
L1[rt]=L1[rt<<1];
if(len1[rt<<1]==ll){
L1[rt]+=L1[rt<<1|1];
}
R1[rt]=R1[rt<<1|1];
if(len1[rt<<1|1]==rr){
R1[rt]+=R1[rt<<1];
}
}
void push_down(int rt,int l,int r){
if(lazy[rt]==1){
swap(len0[rt<<1],len1[rt<<1]);
swap(L0[rt<<1],L1[rt<<1]);
swap(R0[rt<<1],R1[rt<<1]);
swap(len0[rt<<1|1],len1[rt<<1|1]);
swap(L0[rt<<1|1],L1[rt<<1|1]);
swap(R0[rt<<1|1],R1[rt<<1|1]);
lazy[rt<<1]^=1;
lazy[rt<<1|1]^=1;
lazy[rt]=0;
}
}
void build(int rt,int l,int r){
if(l==r){
if(a[l]==0){
len0[rt]=L0[rt]=R0[rt]=1;
len1[rt]=L1[rt]=R1[rt]=0;
}
if(a[l]==1){
len0[rt]=L0[rt]=R0[rt]=0;
len1[rt]=L1[rt]=R1[rt]=1;
}
lazy[rt]=0;
return ;
}
int m=(l+r)>>1;
build(rt<<1,l,m);
build(rt<<1|1,m+1,r);
push_up(rt,l,r);
}
void update(int rt,int l,int r,int ll,int rr){
if(ll<=l&&r<=rr){
swap(len0[rt],len1[rt]);
swap(L0[rt],L1[rt]);
swap(R0[rt],R1[rt]);
lazy[rt]^=1;
return ;
}
push_down(rt,l,r);
int m=(l+r)>>1;
if(ll<=m) update(rt<<1,l,m,ll,rr);
if(m<rr) update(rt<<1|1,m+1,r,ll,rr);
push_up(rt,l,r);
}
int query(int rt,int l,int r,int ll,int rr){
if(ll<=l&&r<=rr){
return len1[rt];
}
push_down(rt,l,r);
int m=(l+r)>>1;
if(rr<=m) return query(rt<<1,l,m,ll,rr);
if(ll>m) return query(rt<<1|1,m+1,r,ll,rr);
int ls=query(rt<<1,l,m,ll,rr);
int rs=query(rt<<1|1,m+1,r,ll,rr);
int lll=R1[rt<<1];
if(lll>m-ll+1) lll=m-ll+1;
int rrr=L1[rt<<1|1];
if(rrr>rr-(m+1)+1) rrr=rr-(m+1)+1;
return max(max(ls,rs),lll+rrr);
// return res;
}
void init(){
memset(a,0,sizeof 0);
memset(len0,0,sizeof len0);
memset(L0,0,sizeof L0);
memset(R0,0,sizeof R0);
memset(len1,0,sizeof len1);
memset(L1,0,sizeof L1);
memset(R1,0,sizeof R1);
memset(lazy,0,sizeof lazy);
}
int main(){
int n;
while(scanf("%d",&n)==1){
init();
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
build(1,1,n);
int m;
scanf("%d",&m);
int opt,l,r;
for(int i=1;i<=m;i++){
scanf("%d%d%d",&opt,&l,&r);
if(opt==1){
update(1,1,n,l,r);
}
if(opt==0){
cout<<query(1,1,n,l,r)<<endl;
}
}
}
}
Sequence operation
题意:
区间改值+异或,区间求和+区间最长串。
ac代码
#include<bits/stdc++.h>
using namespace std;
const int maxn=100010;
int sum[maxn<<2],a[maxn<<2];
int len0[maxn<<2],L0[maxn<<2],R0[maxn<<2];
int len1[maxn<<2],L1[maxn<<2],R1[maxn<<2];
int lazya[maxn<<2],lazyb[maxn<<2]; //a覆盖 b反转
void push_up(int rt,int l,int r){
sum[rt]=sum[rt<<1]+sum[rt<<1|1];//sum
len0[rt]=max(len0[rt<<1],len0[rt<<1|1]);//len0
len0[rt]=max(len0[rt],R0[rt<<1]+L0[rt<<1|1]);
len1[rt]=max(len1[rt<<1],len1[rt<<1|1]);//len1
len1[rt]=max(len1[rt],R1[rt<<1]+L1[rt<<1|1]);
//cout<<rt<<" "<<len1[rt]<<endl;
int m=(l+r)>>1,ll=m-l+1,rr=r-m;
L0[rt]=L0[rt<<1];//L R0
if(L0[rt<<1]==ll){
L0[rt]+=L0[rt<<1|1];
}
R0[rt]=R0[rt<<1|1];
if(R0[rt<<1|1]==rr){
R0[rt]+=R0[rt<<1];
}
L1[rt]=L1[rt<<1];//L R1
if(L1[rt<<1]==ll){
L1[rt]+=L1[rt<<1|1];
}
R1[rt]=R1[rt<<1|1];
if(R1[rt<<1|1]==rr){
R1[rt]+=R1[rt<<1];
}
return ;
}
void build(int rt,int l,int r){
lazya[rt]=-1;
lazyb[rt]=0;
if(l==r){
sum[rt]=a[l];
lazya[rt]=-1;
lazyb[rt]=0;
if(a[l]==0){
len0[rt]=L0[rt]=R0[rt]=1;
len1[rt]=L1[rt]=R1[rt]=0;
}
else {
len0[rt]=L0[rt]=R0[rt]=0;
len1[rt]=L1[rt]=R1[rt]=1;
}
return ;
}
int m=(l+r)>>1;
build(rt<<1,l,m);
build(rt<<1|1,m+1,r);
push_up(rt,l,r);
return ;
}
void push_down(int rt,int l,int r){
if(lazya[rt]!=-1){
int v=lazya[rt],m=(l+r)>>1;
sum[rt<<1]=v*(m-l+1);
sum[rt<<1|1]=v*(r-m);
if(v==0){
len0[rt<<1]=L0[rt<<1]=R0[rt<<1]=m-l+1;
len1[rt<<1]=L1[rt<<1]=R1[rt<<1]=0;
len0[rt<<1|1]=L0[rt<<1|1]=R0[rt<<1|1]=r-m;
len1[rt<<1|1]=L1[rt<<1|1]=R1[rt<<1|1]=0;
}
if(v==1){
len0[rt<<1]=L0[rt<<1]=R0[rt<<1]=0;
len1[rt<<1]=L1[rt<<1]=R1[rt<<1]=m-l+1;
len0[rt<<1|1]=L0[rt<<1|1]=R0[rt<<1|1]=0;
len1[rt<<1|1]=L1[rt<<1|1]=R1[rt<<1|1]=r-m;
}
lazya[rt<<1]=lazya[rt<<1|1]=v;
lazyb[rt<<1]=lazyb[rt<<1|1]=0;
lazya[rt]=-1;
}
if(lazyb[rt]==1){
int m=(l+r)>>1;
sum[rt<<1]=m-l+1-sum[rt<<1];
sum[rt<<1|1]=r-m-sum[rt<<1|1];
swap(len0[rt<<1],len1[rt<<1]);//左
swap(L0[rt<<1],L1[rt<<1]);
swap(R0[rt<<1],R1[rt<<1]);
swap(len0[rt<<1|1],len1[rt<<1|1]);//右
swap(L0[rt<<1|1],L1[rt<<1|1]);
swap(R0[rt<<1|1],R1[rt<<1|1]);
lazyb[rt<<1]^=1;
lazyb[rt<<1|1]^=1;
lazyb[rt]=0;
}
return ;
}
void update(int rt,int l,int r,int ll,int rr,int kind,int v){
if(ll<=l&&r<=rr){
if(kind==1){
sum[rt]=v*(r-l+1);
lazya[rt]=v;
if(v==0){
len0[rt]=L0[rt]=R0[rt]=r-l+1;
len1[rt]=L1[rt]=R1[rt]=0;
}
if(v==1){
len0[rt]=L0[rt]=R0[rt]=0;
len1[rt]=L1[rt]=R1[rt]=r-l+1;
}
lazyb[rt]=0;
}
if(kind==2){
sum[rt]=r-l+1-sum[rt];
swap(len0[rt],len1[rt]);
swap(L0[rt],L1[rt]);
swap(R0[rt],R1[rt]);
if(lazya[rt]==-1)
lazyb[rt]^=1;
else
lazya[rt]^=1;
}
return ;
}
push_down(rt,l,r);
int m=(l+r)>>1;
if(ll<=m) update(rt<<1,l,m,ll,rr,kind,v);
if(m<rr) update(rt<<1|1,m+1,r,ll,rr,kind,v);
push_up(rt,l,r);
}
int query_sum(int rt,int l,int r,int ll,int rr){
if(ll<=l&&r<=rr){
return sum[rt];
}
push_down(rt,l,r);
int m=(l+r)>>1;
int res=0;
if(ll<=m) res+=query_sum(rt<<1,l,m,ll,rr);
if(m<rr) res+=query_sum(rt<<1|1,m+1,r,ll,rr);
return res;
}
int query_seq(int rt,int l,int r,int ll,int rr){
if(ll<=l&&r<=rr){
return len1[rt];
}
push_down(rt,l,r);
int m=(l+r)>>1;
int res=0;
if(rr<=m) return query_seq(rt<<1,l,m,ll,rr);
if(m<ll) return query_seq(rt<<1|1,m+1,r,ll,rr);
int ls=query_seq(rt<<1,l,m,ll,rr);
int rs=query_seq(rt<<1|1,m+1,r,ll,rr);
int lll=R1[rt<<1];
if(m-ll+1<R1[rt<<1]) lll=m-ll+1;
int rrr=L1[rt<<1|1];
if(rr-(m+1)+1<L1[rt<<1|1]) rrr=rr-(m+1)+1;
return max(max(ls,rs),lll+rrr);
}
void init(){
memset(lazya,-1,sizeof lazya);
memset(lazyb,0,sizeof lazyb);
}
int main(){
int t;
scanf("%d",&t);
while(t--){
// init();
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
build(1,1,n);
int opt,l,r;
// cout<<len1[1]<<endl;
for(int i=1;i<=m;i++){
scanf("%d%d%d",&opt,&l,&r);
l++,r++;
if(opt==0){
update(1,1,n,l,r,1,0);
}
if(opt==1){
update(1,1,n,l,r,1,1);
}
if(opt==2){
update(1,1,n,l,r,2,1);
}
if(opt==3){
printf("%d\n",query_sum(1,1,n,l,r));
}
if(opt==4){
printf("%d\n",query_seq(1,1,n,l,r));
}
}
}
return 0;
}
LCIS
题意:
给出一段n长初始数列,q次操作:修改点或查询区间最长的连续子串。
解析:
增加两个数组,表示区间左右端点的值。然后是查询区间最长串。唯一一道1a题…
ac代码
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
int len[maxn<<2],L[maxn<<2],R[maxn<<2],Ln[maxn<<2],Rn[maxn<<2],a[maxn];
char opt[20];
void push_up(int rt,int l,int r){
len[rt]=max(len[rt<<1],len[rt<<1|1]);
if(Rn[rt<<1]<Ln[rt<<1|1])
len[rt]=max(len[rt],R[rt<<1]+L[rt<<1|1]);
int m=(l+r)>>1,ll=m-l+1,rr=r-m;
L[rt]=L[rt<<1];
if(L[rt<<1]==ll&&Rn[rt<<1]<Ln[rt<<1|1]){
L[rt]+=L[rt<<1|1];
}
R[rt]=R[rt<<1|1];
if(R[rt<<1|1]==rr&&Rn[rt<<1]<Ln[rt<<1|1]){
R[rt]+=R[rt<<1];
}
Ln[rt]=Ln[rt<<1];
Rn[rt]=Rn[rt<<1|1];
}
void build(int rt,int l,int r){
if(l==r){
len[rt]=L[rt]=R[rt]=1;
Ln[rt]=a[l];
Rn[rt]=a[l];
return ;
}
int m=(l+r)>>1;
build(rt<<1,l,m);
build(rt<<1|1,m+1,r);
push_up(rt,l,r);
}
void update(int rt,int l,int r,int pos,int v){
if(l==r){
// cout<<"in"<<endl;
len[rt]=L[rt]=R[rt]=1;
Ln[rt]=Rn[rt]=v;
return ;
}
int m=(l+r)>>1;
if(pos<=m) update(rt<<1,l,m,pos,v);
if(pos>m) update(rt<<1|1,m+1,r,pos,v);
push_up(rt,l,r);
}
int query(int rt,int l,int r,int ll,int rr){
if(ll<=l&&r<=rr){
return len[rt];
}
int m=(l+r)>>1;
int res=0;
if(rr<=m) return query(rt<<1,l,m,ll,rr);
if(m<ll) return query(rt<<1|1,m+1,r,ll,rr);
int ls=query(rt<<1,l,m,ll,rr);
int rs=query(rt<<1|1,m+1,r,ll,rr);
int ms=0;
if(Rn[rt<<1]<Ln[rt<<1|1]){
int lll=R[rt<<1];
if(m-ll+1<R[rt<<1]) lll=m-ll+1;
int rrr=L[rt<<1|1];
if(rr-(m+1)+1<L[rt<<1|1]) rrr=rr-(m+1)+1;
ms=lll+rrr;
}
return max(max(ls,rs),ms);
}
int main(){
int t;
scanf("%d",&t);
while(t--){
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
build(1,1,n);
while(m--){
scanf("%s",&opt);
if(opt[0]=='Q'){
int l,r;
scanf("%d%d",&l,&r);l++,r++;
cout<<query(1,1,n,l,r)<<endl;
}
if(opt[0]=='U'){
int pos,x;
scanf("%d%d",&pos,&x);pos++;
update(1,1,n,pos,x);
}
}
}
return 0;
}