线段树题目乱堆
联
题意
范围$1e18$
题解
首先看到范围这么大,肯定要离散化的,
发现最后最左面0位置只可能修改过的位置-1,+1,等,不可能在一段区间中间凭空出现
于是可以这样离散化
if(l[i]!=1) lsh[++lsh[0]]=l[i]-1; lsh[++lsh[0]]=l[i]; lsh[++lsh[0]]=r[i]; lsh[++lsh[0]]=r[i]+1;
然后考虑如何维护
两种方法:
1.维护最左0出现位置,最左1出现位置
这样异或操作就swap一下就好了
我没打这种
2.维护区间0个数,
这样异或操作就转化成了区间长度-0个数
查询如果左子树有0优先走左子树,否则走右子树,递归到叶子
3.keduoli树水过
这里用的第2种方法
两种懒标记不可同时存在,
down
void down(ll x){ // printf("l=%lld r=%lld tr[lson].f1=%lld tr[rson].f1=%lld\n",tr[x].l,tr[x].r,tr[x<<1].f1,tr[x<<1|1].f1); if(tr[x].f1){ if(tr[x<<1].f2){ tr[x<<1].f2=0; tr[x<<1].sum=tr[x<<1].len-tr[x<<1].sum; } if(tr[x<<1|1].f2){ tr[x<<1|1].f2=0; tr[x<<1|1].sum=tr[x<<1|1].len-tr[x<<1|1].sum; } tr[x<<1].f1=tr[x].f1; tr[x<<1].sum=((tr[x].f1==2)?tr[x<<1].len:0); tr[x<<1|1].f1=tr[x].f1; tr[x<<1|1].sum=((tr[x].f1==2)?tr[x<<1|1].len:0); } else if(tr[x].f2){//区间异或 if(tr[x<<1].f2){ tr[x<<1].f2=0; tr[x<<1].sum=tr[x<<1].len-tr[x<<1].sum; } else if(tr[x<<1].f1==1){ tr[x<<1].sum=tr[x<<1].len; tr[x<<1].f1=2; tr[x<<1].f2=0; } else if(tr[x<<1].f1==2){ tr[x<<1].sum=0; tr[x<<1].f1=1; tr[x<<1].f2=0; } else tr[x<<1].f2=1,tr[x<<1].sum=tr[x<<1].len-tr[x<<1].sum; if(tr[x<<1|1].f2){ tr[x<<1|1].f2=0; tr[x<<1|1].sum=tr[x<<1|1].len-tr[x<<1|1].sum; } else if(tr[x<<1|1].f1==1){ tr[x<<1|1].sum=tr[x<<1|1].len; tr[x<<1|1].f1=2; tr[x<<1|1].f2=0; } else if(tr[x<<1|1].f1==2){ tr[x<<1|1].sum=0; tr[x<<1|1].f1=1; tr[x<<1|1].f2=0; } else tr[x<<1|1].f2=1,tr[x<<1|1].sum=tr[x<<1|1].len-tr[x<<1|1].sum; } // printf("down*** f1=%lld f2=%lld lson.f2=%lld rson.f2=%lld l=%lld r=%lld tr[x].sum=%lld lson l=%lld r=%lld sum=%lld rson l=%lld r=%lld sum=%lld\n",tr[x].f1,tr[x].f2,tr[x<<1].f2,tr[x<<1|1].f2,tr[x].l,tr[x].r,tr[x].sum,tr[x<<1].l,tr[x<<1].r,tr[x<<1].sum,tr[x<<1|1].l,tr[x<<1|1].r,tr[x<<1|1].sum); // printf("l=%lld r=%lld lson.f1=%lld f2=%lld sum=%lld l=%lld r=%lld rson.f1=%lld f2=%lld sum=%lld\n",tr[x<<1].l,tr[x<<1].r,tr[x<<1].f1,tr[x<<1].f2,tr[x<<1].sum,tr[x<<1|1].l,tr[x<<1|1].r,tr[x<<1|1].f1,tr[x<<1|1].f2,tr[x<<1|1].sum); tr[x].f1=0; tr[x].f2=0; }
注意,这里区间修改因为两种懒标记不可同时存在,所以也要进行这种操作
可能两次都修改同一个区间,这样你上一个标记没下传,这一个标记就又来了
特殊处理一下
代码
#include<bits/stdc++.h> using namespace std; #define ll long long #define A 10010101 ll c[A],l[A],r[A],opt[A],now[A],lsh[A],yuan[A]; ll ans,canqj=1,rest,n,len; struct node{ ll l,r,f1,f2,len,sum,yu; }tr[A]; void up(ll x){ tr[x].sum=tr[x<<1].sum+tr[x<<1|1].sum; // printf("x.l=%lld x.r=%lld tr[x].sum=%lld\n",tr[x].l,tr[x].r,tr[x].sum); } void built(ll x,ll l,ll r){ tr[x].l=l,tr[x].r=r; tr[x].len=r-l+1; if(l==r){ tr[x].sum=1; tr[x].yu=lsh[l]; return; } ll mid=(tr[x].l+tr[x].r)>>1; built(x<<1,l,mid); built(x<<1|1,mid+1,r); up(x); } void down(ll x){ // printf("l=%lld r=%lld tr[lson].f1=%lld tr[rson].f1=%lld\n",tr[x].l,tr[x].r,tr[x<<1].f1,tr[x<<1|1].f1); if(tr[x].f1){ if(tr[x<<1].f2){ tr[x<<1].f2=0; tr[x<<1].sum=tr[x<<1].len-tr[x<<1].sum; } if(tr[x<<1|1].f2){ tr[x<<1|1].f2=0; tr[x<<1|1].sum=tr[x<<1|1].len-tr[x<<1|1].sum; } tr[x<<1].f1=tr[x].f1; tr[x<<1].sum=((tr[x].f1==2)?tr[x<<1].len:0); tr[x<<1|1].f1=tr[x].f1; tr[x<<1|1].sum=((tr[x].f1==2)?tr[x<<1|1].len:0); } else if(tr[x].f2){//区间异或 if(tr[x<<1].f2){ tr[x<<1].f2=0; tr[x<<1].sum=tr[x<<1].len-tr[x<<1].sum; } else if(tr[x<<1].f1==1){ tr[x<<1].sum=tr[x<<1].len; tr[x<<1].f1=2; tr[x<<1].f2=0; } else if(tr[x<<1].f1==2){ tr[x<<1].sum=0; tr[x<<1].f1=1; tr[x<<1].f2=0; } else tr[x<<1].f2=1,tr[x<<1].sum=tr[x<<1].len-tr[x<<1].sum; if(tr[x<<1|1].f2){ tr[x<<1|1].f2=0; tr[x<<1|1].sum=tr[x<<1|1].len-tr[x<<1|1].sum; } else if(tr[x<<1|1].f1==1){ tr[x<<1|1].sum=tr[x<<1|1].len; tr[x<<1|1].f1=2; tr[x<<1|1].f2=0; } else if(tr[x<<1|1].f1==2){ tr[x<<1|1].sum=0; tr[x<<1|1].f1=1; tr[x<<1|1].f2=0; } else tr[x<<1|1].f2=1,tr[x<<1|1].sum=tr[x<<1|1].len-tr[x<<1|1].sum; } // printf("down*** f1=%lld f2=%lld lson.f2=%lld rson.f2=%lld l=%lld r=%lld tr[x].sum=%lld lson l=%lld r=%lld sum=%lld rson l=%lld r=%lld sum=%lld\n",tr[x].f1,tr[x].f2,tr[x<<1].f2,tr[x<<1|1].f2,tr[x].l,tr[x].r,tr[x].sum,tr[x<<1].l,tr[x<<1].r,tr[x<<1].sum,tr[x<<1|1].l,tr[x<<1|1].r,tr[x<<1|1].sum); // printf("l=%lld r=%lld lson.f1=%lld f2=%lld sum=%lld l=%lld r=%lld rson.f1=%lld f2=%lld sum=%lld\n",tr[x<<1].l,tr[x<<1].r,tr[x<<1].f1,tr[x<<1].f2,tr[x<<1].sum,tr[x<<1|1].l,tr[x<<1|1].r,tr[x<<1|1].f1,tr[x<<1|1].f2,tr[x<<1|1].sum); tr[x].f1=0; tr[x].f2=0; } void seg_add(ll x,ll l,ll r,ll val){ // printf("l=%lld r=%lld tr[x].l=%lld tr[x].r=%lld\n",l,r,tr[x].l,tr[x].r); if(tr[x].l>=l&&tr[x].r<=r){ if(val==3){//异或 if(tr[x].f2){ tr[x].f2=0; tr[x].sum=tr[x].len-tr[x].sum; } else if(tr[x].f1==1){ tr[x].sum=tr[x].len; tr[x].f1=2; tr[x].f2=0; } else if(tr[x].f1==2){ tr[x].sum=0; tr[x].f1=1; tr[x].f2=0; } else tr[x].f2=1,tr[x].sum=tr[x].len-tr[x].sum; } else if(val==1){//区间赋值1 tr[x].sum=0; tr[x].f1=1; tr[x].f2=0; } else if(val==2){ tr[x].sum=tr[x].len; tr[x].f1=2; tr[x].f2=0; } // printf("havefindit l=%lld r=%lld val=%lld val=%lld\n",tr[x].l,tr[x].r,tr[x].f1,val); return ; } if(tr[x].f1||tr[x].f2) down(x); ll mid=(tr[x].l+tr[x].r)>>1; if(mid>=l)seg_add(x<<1,l,r,val); if(mid<r) seg_add(x<<1|1,l,r,val); up(x); } void query(ll x){ if(tr[x].l==tr[x].r){ ans=lsh[tr[x].l]; return ; } // printf("query l=%lld r=%lld f1=%lld f2=%lld\n",tr[x].l,tr[x].r,tr[x].f1,tr[x].f2); if(tr[x].f1||tr[x].f2) down(x); if(tr[x<<1].sum) query(x<<1); else query(x<<1|1); up(x); } void check(ll x){ // printf("l=%lld r%lld f1=%lld f2=%lld sum=%lld\n",tr[x].l,tr[x].r,tr[x].f1,tr[x].f2,tr[x].sum); if(tr[x].l==tr[x].r) return ; check(x<<1); check(x<<1|1); } int main(){ scanf("%lld",&n); lsh[++lsh[0]]=1; for(ll i=1;i<=n;i++){ scanf("%lld%lld%lld",&opt[i],&l[i],&r[i]); if(l[i]!=1) lsh[++lsh[0]]=l[i]-1; lsh[++lsh[0]]=l[i]; lsh[++lsh[0]]=r[i]; lsh[++lsh[0]]=r[i]+1; } sort(lsh+1,lsh+lsh[0]+1); len=unique(lsh+1,lsh+lsh[0]+1)-lsh-1; // for(ll i=1;i<=lsh[0];i++){ // printf("lsh[i]=%lld len=%lld\n",lsh[i],len); // } for(ll i=1;i<=n;i++){ l[i]=lower_bound(lsh+1,lsh+len+1,l[i])-lsh; r[i]=lower_bound(lsh+1,lsh+len+1,r[i])-lsh; // printf("l=%lld r=%lld\n",l[i],r[i]); } built(1,1,len); for(ll i=1;i<=n;i++){ seg_add(1,l[i],r[i],opt[i]); query(1); // check(1); printf("%lld\n",ans); } }
幸运字符
题意
一个由4,7组成字符串,动态最长不下降子序列
区间反转
随便记录4,7,47即可,因为包含翻转所以还要记录74
#include<bits/stdc++.h> using namespace std; #define ll long long #define A 10010010 struct node{ ll l,r,_4,_7,_74,_47,f; }tr[A]; char ch[A],ch2[10]; ll n,m; void up(ll x){ tr[x]._4=tr[x<<1]._4+tr[x<<1|1]._4; tr[x]._7=tr[x<<1]._7+tr[x<<1|1]._7; tr[x]._47=max((tr[x<<1]._4+tr[x<<1|1]._7),max(tr[x<<1]._4+tr[x<<1|1]._47,tr[x<<1]._47+tr[x<<1|1]._7)); tr[x]._74=max((tr[x<<1]._7+tr[x<<1|1]._4),max(tr[x<<1]._74+tr[x<<1|1]._4,tr[x<<1]._7+tr[x<<1|1]._74)); // printf("tr[%lld].l=%lld r=%lld _4=%lld _7=%lld _47=%lld _74=%lld tr[ls].l=%lld r=%lld _4=%lld _7=%lld _47=%lld _74=%lld tr[rs].l=%lld r=%lld _4=%lld _7=%lld _47=%lld _74=%lld\n",x,tr[x].l,tr[x].r,tr[x]._4,tr[x]._7,tr[x]._47,tr[x]._74,tr[x<<1].l,tr[x<<1].r,tr[x<<1]._4,tr[x<<1]._7,tr[x<<1]._47,tr[x<<1]._74,tr[x<<1|1].l,tr[x<<1|1].r,tr[x<<1|1]._4,tr[x<<1|1]._7,tr[x<<1|1]._47,tr[x<<1|1]._74); } void down(ll x){ swap(tr[x<<1]._4,tr[x<<1]._7); swap(tr[x<<1]._47,tr[x<<1]._74); swap(tr[x<<1|1]._4,tr[x<<1|1]._7); swap(tr[x<<1|1]._47,tr[x<<1|1]._74); tr[x<<1].f^=1,tr[x<<1|1].f^=1; tr[x].f=0; } void built(ll x,ll l,ll r){ tr[x].l=l,tr[x].r=r; if(l==r){ if(ch[l]=='4') tr[x]._4=1; else tr[x]._7=1; return ; } ll mid=(l+r)>>1; built(x<<1,l,mid); built(x<<1|1,mid+1,r); up(x); } void change(ll x,ll l,ll r){ if(tr[x].l>=l&&tr[x].r<=r){ swap(tr[x]._4,tr[x]._7); swap(tr[x]._47,tr[x]._74); tr[x].f^=1; return ; } if(tr[x].f) down(x); ll mid=(tr[x].l+tr[x].r)>>1; if(mid>=l)change(x<<1,l,r); if(mid<r) change(x<<1|1,l,r); up(x); } void query(ll x){ printf("tr[x].l=%lld r=%lld _4=%lld _7=%lld _47=%lld _74=%lld\n",tr[x].l,tr[x].r,tr[x]._4,tr[x]._7,tr[x]._47,tr[x]._74); if(tr[x].l==tr[x].r) return ; query(x<<1); query(x<<1|1); } int main(){ // freopen("da.in","r",stdin); // freopen("ans.bf","w",stdout); scanf("%lld%lld",&n,&m); scanf("%s",ch+1); built(1,1,n); // query(1); for(ll i=1;i<=m;i++){ scanf("%s",ch2+1); // printf("i=%lld\n",i); if(ch2[1]=='c'){ ll maxx=max(max(tr[1]._4,tr[1]._7),tr[1]._47); printf("%lld\n",maxx); } else { ll l,r; scanf("%lld%lld",&l,&r); change(1,l,r); } // query(1); } }
线段树维护hash
一般用于必须满足某个顺序时可以用
代码
#include<bits/stdc++.h> #define ll long long #define A 1010100 #define rill 233 using namespace std; struct node{ ll l,r,jz; unsigned ll val; void init(){ jz=0;val=0; } }tr[A]; unsigned ll h[A],p[A]; void built(ll x,ll l,ll r){ tr[x].l=l,tr[x].r=r; tr[x].init(); if(l==r){ tr[x].val=0; return ; } ll mid=(l+r)>>1; built(x<<1,l,mid); built(x<<1|1,mid+1,r); } void down(ll x){// tr[x<<1].jz+=tr[x].jz; tr[x<<1|1].jz+=tr[x].jz; tr[x<<1].val*=p[tr[x].jz]; tr[x<<1|1].val*=p[tr[x].jz]; tr[x<<1].val+=tr[x].val; tr[x<<1|1].val+=tr[x].val; tr[x].jz=0;tr[x].val=0; } void seg_add(ll x,ll l,ll r,ll d){ if(tr[x].l>=l&&tr[x].r<=r){// tr[x].val=tr[x].val*233+d;tr[x].jz++;return ; } if(tr[x].jz) down(x); ll mid=(tr[x].l+tr[x].r)>>1; if(mid>=l)seg_add(x<<1,l,r,d); if(mid<r) seg_add(x<<1|1,l,r,d); } ll n,k,t; ll ans=0; void find(ll x){ if(tr[x].l==tr[x].r){ if(tr[x].val==h[k]) ans++; return ; } if(tr[x].jz) down(x); find(x<<1);find(x<<1|1); } void print(ll x){ printf("l=%lld r=%lld jz=%lld val=",tr[x].l,tr[x].r,tr[x].jz); cout<<tr[x].val<<endl; if(tr[x].l==tr[x].r) return ; print(x<<1);print(x<<1|1); } int main(){ scanf("%lld%lld%lld",&n,&k,&t); p[0]=1; for(ll i=1;i<=k;i++) h[i]=h[i-1]*233+i,p[i]=p[i-1]*233; built(1,1,n); while(t--){ ll l,r,x; scanf("%lld%lld%lld",&l,&r,&x); seg_add(1,l,r,x); // print(1); } find(1); printf("%lld\n",ans); }
我已没有下降的余地