题意:给定的序列 有两个操作 1将其中一段加倍 2询问段中的最长相等数字是多少
解法:直接上线段树就可以了 但是-》边界问题比较麻烦 有两种做法 一种在更新的时候直接判定边界,另外一种则是选定完边界再进行更新,题解的说法里面是第二种啊,但是比赛的时候不敢敲,怕码力不够啊。有点后悔的
首先是麻烦的写法:
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
#define ls (rt<<1)
#define rs (rt<<1|1)
#define mid ((l+r)>>1)
#define ll __int64
#define maxn 55555
ll sum[maxn<<2],mul[maxn<<2],ma[maxn<<2];
void up(int rt,int l,int r){
sum[rt]=sum[ls]+sum[rs];
ma[rt]=max(ma[ls],ma[rs]);
}
void down(int rt,int l,int r){
if(mul[rt]){
sum[ls]<<=mul[rt];
sum[rs]<<=mul[rt];
ma[ls]<<=mul[rt];
ma[rs]<<=mul[rt];
mul[ls]+=mul[rt];
mul[rs]+=mul[rt];
mul[rt]=0;
}
}
void build(int rt,int l,int r){
mul[rt]=0;
if(l==r){
sum[rt]=ma[rt]=(ll)1;
return ;
}
build(ls,l,mid);
build(rs,mid+1,r);
up(rt,l,r);
}
int queryl(int rt,int l,int r,ll w){
if(l==r)return l;
down(rt,l,r);
if(sum[ls]>=w){
return queryl(ls,l,mid,w);
}else return queryl(rs,mid+1,r,w-sum[ls]);
}
void ins(int rt,int l,int r,int L,int R){
if(L<=l&&r<=R){
sum[rt]<<=1;
ma[rt]<<=1;
mul[rt]++;
return ;
}down(rt,l,r);
if(L<=mid)ins(ls,l,mid,L,R);
if(mid<R)ins(rs,mid+1,r,L,R);
up(rt,l,r);
}
void ins_s(int rt,int l,int r,int L,int R,ll w){
if(L<=l&&r<=R){
sum[rt]+=w;
ma[rt]+=w;
return ;
}down(rt,l,r);
if(L<=mid)ins_s(ls,l,mid,L,R,w);
if(mid<R)ins_s(rs,mid+1,r,L,R,w);
up(rt,l,r);
}
ll querys(int rt,int l,int r,int L,int R){
if(L<=l&&r<=R){
return sum[rt];
}down(rt,l,r);
ll res=0;
if(L<=mid)res+=querys(ls,l,mid,L,R);
if(mid<R)res+=querys(rs,mid+1,r,L,R);
return res;
}
ll query(int rt,int l,int r,int L,int R){
if(L<=l&&r<=R)return ma[rt];
down(rt,l,r);
ll res=0;
if(L<=mid)res=max(res,query(ls,l,mid,L,R));
if(mid<R)res=max(res,query(rs,mid+1,r,L,R));
return res;
}
int n,m;
char op[111];
int main(){
int _;scanf("%d",&_);
for(int z=1;z<=_;++z){
scanf("%d%d",&n,&m);
build(1,1,n);ll l,r;
printf("Case #%d:\n",z);
while(m--){
scanf("%s%I64d%I64d",op,&l,&r);
if(l>r)swap(l,r);
int lf=queryl(1,1,n,l);
int ri=queryl(1,1,n,r);
ll lsum=querys(1,1,n,1,lf),rsum;
if(ri>1)rsum=querys(1,1,n,1,ri-1);
else rsum=0;
// printf("%d %d %lld %lld\n",lf,ri,lsum,rsum);
if(*op=='D'){
if(lf==ri){
ins_s(1,1,n,lf,lf,r-l+1);
}else{
if(lf+1<=ri-1)ins(1,1,n,lf+1,ri-1);
ins_s(1,1,n,lf,lf,lsum-l+1);
ins_s(1,1,n,ri,ri,r-rsum);
}
}
else{
if(lf==ri){
printf("%I64d\n",r-l+1);
}else{
ll maxx=0;
if(lf+1<=ri-1)maxx=max(maxx,query(1,1,n,lf+1,ri-1));
maxx=max(maxx,lsum-l+1);
maxx=max(maxx,r-rsum);
printf("%I64d\n",maxx);
}
}
}
}
return 0;
}
其次是比较简洁的:
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
#define ls (rt<<1)
#define rs (rt<<1|1)
#define mid ((l+r)>>1)
#define ll __int64
#define maxn 55555
int scan()
{
int res=0,ch;
while(!((ch= getchar())>='0'&&ch<='9')){
if(ch==EOF)return 1<<30;
}
res=ch-'0';
while((ch=getchar())>='0'&&ch<='9')
res=res*10+(ch-'0');
return res;
}
ll sum[maxn<<2],mul[maxn<<2],ma[maxn<<2];
void up(int rt,int l,int r){
sum[rt]=sum[ls]+sum[rs];
ma[rt]=max(ma[ls],ma[rs]);
}
void down(int rt,int l,int r){
if(mul[rt]){
sum[ls]<<=mul[rt];
sum[rs]<<=mul[rt];
ma[ls]<<=mul[rt];
ma[rs]<<=mul[rt];
mul[ls]+=mul[rt];
mul[rs]+=mul[rt];
mul[rt]=0;
}
}
void build(int rt,int l,int r){
mul[rt]=0;
if(l==r){
sum[rt]=ma[rt]=(ll)1;
return ;
}
build(ls,l,mid);
build(rs,mid+1,r);
up(rt,l,r);
}
void insr(int rt,int l,int r,ll L,ll R){
if(l==r){
ma[rt]=sum[rt]+=R-L+1;
return ;
}else if(R-L+1==sum[rt]){
sum[rt]<<=1;ma[rt]<<=1;mul[rt]++;
return ;
}down(rt,l,r);
if(sum[ls]>=R)insr(ls,l,mid,L,R);
else if(sum[ls]<L)insr(rs,mid+1,r,L-sum[ls],R-sum[ls]);
else{
insr(rs,mid+1,r,1,R-sum[ls]);
insr(ls,l,mid,L,sum[ls]);
}
up(rt,l,r);
}
ll queryr(int rt,int l,int r,ll L,ll R){
if(l==r)return R-L+1 ;
if(R-L+1==sum[rt])return ma[rt];
down(rt,l,r);
if(sum[ls]>=R)return queryr(ls,l,mid,L,R);
if(sum[ls]<L)return queryr(rs,mid+1,r,L-sum[ls],R-sum[ls]);
return max(queryr(ls,l,mid,L,sum[ls]),queryr(rs,mid+1,r,1,R-sum[ls]));
}
int n,m;
char op[111];
int main(){
int _;scanf("%d",&_);
for(int z=1;z<=_;++z){
scanf("%d%d",&n,&m);
build(1,1,n);ll l,r;
printf("Case #%d:\n",z);
while(m--){
scanf("%s%I64d%I64d",op,&l,&r);
if(*op=='D'){
insr(1,1,n,l,r);
}
else{
printf("%I64d\n",queryr(1,1,n,l,r));
}
}
}
return 0;
}