版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/baidu_36797646/article/details/82853316
前言:
今天突然想学一学这个,那就学一学,资料可以在lzz的uoj博客找到。
核心:
(我只学了区间取
和
,不会历史最值)
以取
为例子,那么我们需要维护区间最大值
,次大值
,最大值出现次数
,区间和
,然后分下面几种情况(设当前区间的值改为
):
1、
,直接返回,无需修改。
2、
,
,返回。
3、直接递归到
个儿子。
复杂度不知道,吉老师说可以证到
,详情见这里。
hdu5306:
这个题比较简单,因为只需要一个最大值标记,直接按照上面说的搞就好了,但是多组数据,注意初始化,我的初始化就有问题,不知为什么,要全清为 才可以。
代码:
#include<bits/stdc++.h>
using namespace std;
#define LL long long
const int Maxn=1000010;
const int inf=2147483647;
int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return x*f;
}
int n,m,a[Maxn];
struct Seg{int l,r,lc,rc,mx,se,c,tag;LL sum;}tr[Maxn<<1];
int len;
void up(int x)
{
int lc=tr[x].lc,rc=tr[x].rc;
tr[x].sum=tr[lc].sum+tr[rc].sum;
if(tr[lc].mx==tr[rc].mx)
{
tr[x].mx=tr[lc].mx;
tr[x].se=max(tr[lc].se,tr[rc].se);
tr[x].c=tr[lc].c+tr[rc].c;
}
else
{
tr[x].mx=max(tr[lc].mx,tr[rc].mx);
tr[x].se=max(tr[lc].se,tr[rc].se);
tr[x].se=max(tr[x].se,((tr[lc].mx>tr[rc].mx)?tr[rc].mx:tr[lc].mx));
tr[x].c=((tr[lc].mx>tr[rc].mx)?tr[lc].c:tr[rc].c);
}
}
bool work(int x,int v)
{
if(tr[x].mx<=v)return true;
if(tr[x].se<v)
{
tr[x].sum-=(LL)tr[x].c*(tr[x].mx-v);
tr[x].mx=tr[x].tag=v;
return true;
}
return false;
}
void down(int x)
{
int lc=tr[x].lc,rc=tr[x].rc;
work(lc,tr[x].tag),work(rc,tr[x].tag);
tr[x].tag=-1;
}
void build(int l,int r)
{
int t=++len;
tr[t].l=l;tr[t].r=r;tr[t].tag=-1;
if(l==r){tr[t].sum=tr[t].mx=a[l];tr[t].c=1;tr[t].se=-1;return;}
int mid=l+r>>1;
tr[t].lc=len+1,build(l,mid);
tr[t].rc=len+1,build(mid+1,r);
up(t);
}
void modify(int x,int l,int r,int v)
{
int mid=tr[x].l+tr[x].r>>1,lc=tr[x].lc,rc=tr[x].rc;
if(tr[x].tag!=-1)down(x);
if(l<=tr[x].l&&tr[x].r<=r)
{
if(work(x,v))return;
modify(lc,l,mid,v),modify(rc,mid+1,r,v);
up(x);
return;
}
if(r<=mid)modify(lc,l,r,v);
else if(l>mid)modify(rc,l,r,v);
else modify(lc,l,mid,v),modify(rc,mid+1,r,v);
up(x);
}
LL query(int x,int l,int r,int o)
{
int mid=tr[x].l+tr[x].r>>1,lc=tr[x].lc,rc=tr[x].rc;
if(tr[x].tag!=-1)down(x);
if(tr[x].l==l&&tr[x].r==r)
{
if(!o)return tr[x].mx;
return tr[x].sum;
}
if(r<=mid)return query(lc,l,r,o);
if(l>mid)return query(rc,l,r,o);
if(o)return query(lc,l,mid,o)+query(rc,mid+1,r,o);
return max(query(lc,l,mid,o),query(rc,mid+1,r,o));
}
int main()
{
int T=read();
while(T--)
{
n=read(),m=read();
for(int i=1;i<=n;i++)a[i]=read();
for(int i=1;i<=(n<<1);i++)tr[i].lc=tr[i].rc=tr[i].mx=tr[i].se=tr[i].tag=tr[i].sum=tr[i].c=0;
len=0;
build(1,n);
while(m--)
{
int op=read(),l=read(),r=read();
if(op)printf("%lld\n",query(1,l,r,op-1));
else modify(1,l,r,read());
}
}
}
bzoj4695:
这个复杂一点,要同时维护最大最小、次大次小这些标记,区间取 或 的时候可能对这些值都有影响,都要维护到,而且感觉有点儿卡常数,加了些优化才过的。
代码:
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define lc (x<<1)
#define rc (x<<1|1)
const int Maxn=500010;
const int inf=2147483647;
int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return x*f;
}
void write(LL x)
{
if(x==0){putchar('0');putchar('\n');return;}
if(x<0)putchar('-'),x=-x;
int a[20],l=0;
while(x)a[++l]=x%10+48,x/=10;
for(int i=l;i;i--)putchar(a[i]);
putchar('\n');
}
int n,m,a[Maxn];
struct Seg{int l,r,mx,mn,cmx,cmn;LL mx1,mn1,sum,tag;}tr[Maxn<<2];
int len=0;
void up(int x)
{
tr[x].sum=tr[lc].sum+tr[rc].sum;
if(tr[lc].mx==tr[rc].mx)
{
tr[x].mx=tr[lc].mx;
tr[x].mx1=max(tr[lc].mx1,tr[rc].mx1);
tr[x].cmx=tr[lc].cmx+tr[rc].cmx;
}
else
{
tr[x].mx=max(tr[lc].mx,tr[rc].mx);
tr[x].mx1=max(tr[lc].mx1,tr[rc].mx1);
tr[x].mx1=max(tr[x].mx1,(LL)((tr[lc].mx>tr[rc].mx)?tr[rc].mx:tr[lc].mx));
tr[x].cmx=((tr[lc].mx>tr[rc].mx)?tr[lc].cmx:tr[rc].cmx);
}
if(tr[lc].mn==tr[rc].mn)
{
tr[x].mn=tr[lc].mn;
tr[x].mn1=min(tr[lc].mn1,tr[rc].mn1);
tr[x].cmn=tr[lc].cmn+tr[rc].cmn;
}
else
{
tr[x].mn=min(tr[lc].mn,tr[rc].mn);
tr[x].mn1=min(tr[lc].mn1,tr[rc].mn1);
tr[x].mn1=min(tr[x].mn1,(LL)((tr[lc].mn>tr[rc].mn)?tr[lc].mn:tr[rc].mn));
tr[x].cmn=((tr[lc].mn>tr[rc].mn)?tr[rc].cmn:tr[lc].cmn);
}
}
bool w1(int x,int v)
{
if(tr[x].mx<=v)return true;
if(tr[x].mx==tr[x].mn)
{
tr[x].mx=tr[x].mn=v;
tr[x].cmx=tr[x].cmn=tr[x].r-tr[x].l+1;
tr[x].mx1=-(1LL<<62),tr[x].mn1=(1LL<<62);
tr[x].sum=(LL)tr[x].cmx*v;
return true;
}
if(tr[x].mx1<v)
{
tr[x].sum-=(LL)tr[x].cmx*(tr[x].mx-v);
tr[x].mx=v;tr[x].mn1=min(tr[x].mn1,(LL)v);tr[x].mn=min(tr[x].mn,v);
return true;
}
return false;
}
bool w2(int x,int v)
{
if(tr[x].mn>=v)return true;
if(tr[x].mx==tr[x].mn)
{
tr[x].mx=tr[x].mn=v;
tr[x].cmx=tr[x].cmn=tr[x].r-tr[x].l+1;
tr[x].mx1=-(1LL<<62),tr[x].mn1=(1LL<<62);
tr[x].sum=(LL)tr[x].cmx*v;
return true;
}
if(tr[x].mn1>v)
{
tr[x].sum+=(LL)tr[x].cmn*(v-tr[x].mn);
tr[x].mn=v;tr[x].mx1=max(tr[x].mx1,(LL)v);tr[x].mx=max(tr[x].mx,v);
return true;
}
return false;
}
void Add(int x,LL v)
{
tr[x].mx+=v,tr[x].mn+=v,tr[x].mx1+=v,tr[x].mn1+=v;
tr[x].sum+=v*(tr[x].r-tr[x].l+1);
tr[x].tag+=v;
}
void down(int x)
{
if(tr[x].tag)Add(lc,tr[x].tag),Add(rc,tr[x].tag),tr[x].tag=0;
if(tr[lc].mx>tr[x].mx)w1(lc,tr[x].mx);
if(tr[rc].mx>tr[x].mx)w1(rc,tr[x].mx);
if(tr[lc].mn<tr[x].mn)w2(lc,tr[x].mn);
if(tr[rc].mn<tr[x].mn)w2(rc,tr[x].mn);
}
void build(int x,int l,int r)
{
tr[x].l=l;tr[x].r=r;tr[x].tag=0;
if(l==r)
{tr[x].sum=tr[x].mx=tr[x].mn=a[l];tr[x].cmx=tr[x].cmn=1;tr[x].mx1=-(1LL<<62);tr[x].mn1=(1LL<<62);return;}
int mid=l+r>>1;
build(lc,l,mid);
build(rc,mid+1,r);
up(x);
}
void add(int x,int l,int r,int v)
{
if(tr[x].l!=tr[x].r)down(x);
if(tr[x].l==l&&tr[x].r==r){Add(x,v);return;}
int mid=tr[x].l+tr[x].r>>1;
if(r<=mid)add(lc,l,r,v);
else if(l>mid)add(rc,l,r,v);
else add(lc,l,mid,v),add(rc,mid+1,r,v);
up(x);
}
void m1(int x,int l,int r,int v)
{
if(tr[x].mx<=v)return;
int mid=tr[x].l+tr[x].r>>1;
if(tr[x].l!=tr[x].r)down(x);
if(l<=tr[x].l&&tr[x].r<=r)
{
if(w1(x,v))return;
m1(lc,l,mid,v),m1(rc,mid+1,r,v);
up(x);
return;
}
if(r<=mid)m1(lc,l,r,v);
else if(l>mid)m1(rc,l,r,v);
else m1(lc,l,mid,v),m1(rc,mid+1,r,v);
up(x);
}
void m2(int x,int l,int r,int v)
{
if(tr[x].mn>=v)return;
int mid=tr[x].l+tr[x].r>>1;
if(tr[x].l!=tr[x].r)down(x);
if(l<=tr[x].l&&tr[x].r<=r)
{
if(w2(x,v))return;
m2(lc,l,mid,v),m2(rc,mid+1,r,v);
up(x);
return;
}
if(r<=mid)m2(lc,l,r,v);
else if(l>mid)m2(rc,l,r,v);
else m2(lc,l,mid,v),m2(rc,mid+1,r,v);
up(x);
}
LL query(int x,int l,int r,int o)
{
int mid=tr[x].l+tr[x].r>>1;
if(tr[x].l!=tr[x].r)down(x);
if(tr[x].l==l&&tr[x].r==r)
{
if(!o)return tr[x].sum;
if(o==1)return tr[x].mx;
return tr[x].mn;
}
if(r<=mid)return query(lc,l,r,o);
if(l>mid)return query(rc,l,r,o);
if(!o)return query(lc,l,mid,o)+query(rc,mid+1,r,o);
if(o==1)return max(query(lc,l,mid,o),query(rc,mid+1,r,o));
return min(query(lc,l,mid,o),query(rc,mid+1,r,o));
}
int main()
{
n=read();
for(int i=1;i<=n;i++)a[i]=read();
build(1,1,n);
m=read();
while(m--)
{
int op=read(),l=read(),r=read();
if(op>3)write(query(1,l,r,op-4));
else
{
int x=read();
if(op==1)add(1,l,r,x);
else if(op==2)m2(1,l,r,x);
else m1(1,l,r,x);
}
}
}