题解 P5251 【[LnOI2019]第二代图灵机】
珂朵莉树+线段树+树状数组。
好毒瘤的题……卡了一页的常数……常数大真的伤不起啊……
首先题目已经非常明显告诉你要用珂朵莉树了,那么我们考虑其他的东西怎么存。
首先要维护区间和,用线段树可以做,但是我们考虑一下还是用树状数组吧,空间常数比较小一点……然后要维护区间最值,这个直接用线段树就行了,不谈。
至于如何查询,建议百度“尺取法”进行学习。
// luogu-judger-enable-o2
#pragma GCC optimize("Ofast")
#include<bits/stdc++.h>
#define MAXN 100005
#define inf 2147483647
#define getchar() (p1==p2 && (p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
char buf[1<<21],*p1=buf,*p2=buf;
char sr[1<<21],z[20];
int C=-1,Z;
using namespace std;
int n,m,col,a[MAXN];
template <typename T> void Read(T &x)
{
x=0;
register int fu=1;
char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if(ch=='-') fu=-1;
for(;isdigit(ch);ch=getchar()) x=(x<<3)+(x<<1)+(ch-48);
x*=fu;
}
inline void Ot()
{
fwrite(sr,1,C+1,stdout);
C=-1;
}
inline void Print(int x,char chr='\n')
{
if(C>1<<20) Ot();
if(x<0)
{
sr[++C]='-';
x=-x;
}
while(z[++Z]=x%10+48,x/=10);
while(sr[++C]=z[Z],--Z);
sr[++C]=chr;
}
struct TreeArray
{
int c[MAXN];
inline int lowbit(register int x)
{
return x&-x;
}
inline void Modify(register int x,register int val)
{
for(;x<=n;x+=lowbit(x)) c[x]+=val;
}
inline int Get(register int x)
{
register int res=0;
for(;x;x-=lowbit(x)) res+=c[x];
return res;
}
inline int Query(register int l,register int r)
{
return Get(r)-Get(l-1);
}
}TA;
struct SegmentTree
{
int t[MAXN<<3];
inline void PushUp(register int rt)
{
t[rt]=max(t[rt<<1],t[rt<<1|1]);
}
void Modify(register int rt,register int l,register int r,register int pos,register int val)
{
if(l==r)
{
t[rt]=val;
return;
}
register int mid=l+r>>1;
if(pos<=mid) Modify(rt<<1,l,mid,pos,val);
else Modify(rt<<1|1,mid+1,r,pos,val);
PushUp(rt);
}
int Query(register int rt,register int l,register int r,register int tl,register int tr)
{
if(tl<=l && r<=tr) return t[rt];
register int mid=l+r>>1,res=0;
if(tl<=mid) res=max(res,Query(rt<<1,l,mid,tl,tr));
if(tr>mid) res=max(res,Query(rt<<1|1,mid+1,r,tl,tr));
return res;
}
}T;
#define iter set<Node>::iterator
struct Node
{
int l,r;
mutable int val;
friend bool operator < (const Node &x,const Node &y)
{
return x.l<y.l;
}
};
set <Node> s;
inline iter Split(register int pos)
{
iter it=s.lower_bound((Node){pos,pos,-1});
if(it!=s.end() && it->l==pos) return it;
--it;
Node x=*it;
s.erase(it);
s.insert((Node){x.l,pos-1,x.val});
return s.insert((Node){pos,x.r,x.val}).first;
}
inline void Assign(register int l,register int r,register int val)
{
iter R=Split(r+1),L=Split(l);
s.erase(L,R);
s.insert((Node){l,r,val});
}
inline int Query1(register int l,register int r)
{
memset(a,0,sizeof(a));
register int res=inf,cnt=col;
iter R=Split(r+1),L=Split(l);
--L;
iter i=L,j=L;
while(j!=R)
{
if(i!=L && --a[i->val]==0) ++cnt;
++i;
while(cnt && j!=R)
{
++j;
if(++a[j->val]==1) --cnt;
}
if(j==R) break;
while(!cnt && i!=j)
{
if(--a[i->val]==0) ++cnt;
++i;
}
if(cnt)
{
--i;
--cnt;
++a[i->val];
}
res=min(res,TA.Query(i->r,j->l));
}
return res;
}
inline bool Check(iter l,iter r)
{
if(l==r) return 1;
++l;
for(iter it=l;it!=r;++it) if(it->r!=it->l) return 0;
return 1;
}
inline int Query2(register int l,register int r)
{
memset(a,0,sizeof(a));
register int res=T.Query(1,1,n,l,r);
iter R=Split(r+1),L=Split(l);
iter i=L,j=L;
while(j!=R)
{
++a[j->val];
while(!Check(i,j))
{
--a[i->val];
++i;
}
while(i!=j && a[j->val]>1)
{
--a[i->val];
++i;
}
if(i!=j) res=max(res,TA.Query(i->r,j->l));
++j;
}
return res;
}
int main()
{
Read(n);
Read(m);
Read(col);
s.insert((Node){0,0,-1});
s.insert((Node){n+1,n+1,-1});
for(register int i=1;i<=n;++i)
{
register int x;
Read(x);
TA.Modify(i,x);
T.Modify(1,1,n,i,x);
}
for(register int i=1;i<=n;++i)
{
register int x;
Read(x);
s.insert((Node){i,i,x});
}
while(m--)
{
register int opt,x,y,z;
Read(opt);
Read(x);
Read(y);
if(opt==1)
{
TA.Modify(x,y-TA.Query(x,x));
T.Modify(1,1,n,x,y);
}
else if(opt==2)
{
Read(z);
Assign(x,y,z);
}
else if(opt==3)
{
register int res=Query1(x,y);
Print(res==inf?-1:res);
}
else if(opt==4)
{
register int res=Query2(x,y);
Print(res);
}
}
return Ot(),0;
}