多校第十二场 题解
Posted skyh
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了多校第十二场 题解相关的知识,希望对你有一定的参考价值。
A. string
对于这类字符串匹配题,有个套路是直接用 (FFT) 优化。
然后发现这题字符集很小,所以枚举一个字符,将匹配串中的这个字符设为 (1),模式串中的非这个字符设为 (1)。
然后用一些技巧优化一下,就可以用 (|sum|+1) 次长度为 (n) 的 (DFT) 求出答案了。
?
B. Tree
容易发现这题就是通过与 (LCT) 类似的树构造出深度和最大的原树。
若一个节点在实链上,我们只关注每个深度的当前最大值。
若一个节点上面是虚边,我们只需要这个节点作为 (splay) 根节点的当前最大值。
所以可以设计一个 (dp), (dp_{i,j}) 表示以 (i) 为根节点,(splay) 大小为 (j) 的最大值。
(f_i=max limits_{j=1}^{sz_i}dp_{i,j}) 这个玩意表示若 (i) 为虚子树的最大值。
发现转移主要与左子树有关,因为左子树贡献了一些深度。
所以枚举左子树是谁,枚举左子树的大小就行了。
?
C. sort
如果只有排序操作,一个方法是这样的。
开一个平衡树维护已经排好序的每个连续段。
对于每个连续段,用 平衡树/(01trie) 等来实现分裂,暴力去合并复杂度就是对的。
拓展到本题上,仍然使用平衡树套 (01trie)。
在平衡树上打标记,表示对子树内所有 (01trie) 都进行这种操作。
在 (01trie) 上也打标记,表示对子树内节点进行这种操作。
可以认为,平衡树上的标记是上次排序到这次排序之间的,也就是说不影响相对关系的。
而 (01trie) 上的标记是上次排序之前的,也就是说影响相对关系。
所以当 (01trie) 上标记下传的时候,需要交换两个儿子或者合并两个儿子。
对于修改操作,只需要在区间的平衡树上打个标记。
对于排序操作,可以暴力拉出来每个连续段,把它上面的标记打在 (01trie) 上,并合并在一起。
思路大概就是这样,打起来有点恶心。
?
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+7;
int n,m;
int a[N];
struct Tag{
int A,B,C;
Tag():A(-1),B(0),C(0){}
inline friend void operator *= (Tag &a,const Tag &b){
a.A&=b.A; a.B&=b.A; a.C&=b.A;
a.B|=b.B; a.C&=-1^b.B; a.C^=b.C;
}
inline int mp(int k,int f){
return ((f&(A>>k&1))|(B>>k&1))^(C>>k&1);
}
};
namespace Trie{
int cnt;
int ch[N*180][2],sz[N*180];
Tag lzy[N*180];
inline void down(int p);
inline int merge(int x,int y,int dep);
inline void insert(int p,int x){
for(int i=31;~i;--i){
if(!ch[p][x>>i&1]) ch[p][x>>i&1]=++cnt;
++sz[p]; p=ch[p][x>>i&1];
} ++sz[p];
}
inline void update(int p){
sz[p]=sz[ch[p][0]]+sz[ch[p][1]];
}
inline void down(int p,int dep){
lzy[ch[p][0]]*=lzy[p]; lzy[ch[p][1]]*=lzy[p];
if(lzy[p].mp(dep-1,0)==1&&lzy[p].mp(dep-1,1)==0) swap(ch[p][0],ch[p][1]);
else if(lzy[p].mp(dep-1,0)==0&&lzy[p].mp(dep-1,1)==0) ch[p][0]=merge(ch[p][0],ch[p][1],dep-1),ch[p][1]=0;
else if(lzy[p].mp(dep-1,0)==1&&lzy[p].mp(dep-1,1)==1) ch[p][1]=merge(ch[p][0],ch[p][1],dep-1),ch[p][0]=0;
lzy[p]=Tag();
}
inline int merge(int x,int y,int dep){
if(!x||!y) return x|y;
sz[x]+=sz[y]; if(!dep) return x;
down(x,dep); down(y,dep);
ch[x][0]=merge(ch[x][0],ch[y][0],dep-1);
ch[x][1]=merge(ch[x][1],ch[y][1],dep-1);
return update(x),x;
}
inline void split(int p,int k,int dep,int &x,int &y){
if(!dep) return x=++cnt,y=++cnt,sz[x]=k,sz[y]=sz[p]-k,void();
down(p,dep); x=++cnt; y=++cnt;
if(sz[ch[p][0]]>=k) split(ch[p][0],k,dep-1,ch[x][0],ch[y][0]),ch[y][1]=ch[p][1],update(x),update(y);
else split(ch[p][1],k-sz[ch[p][0]],dep-1,ch[x][1],ch[y][1]),ch[x][0]=ch[p][0],update(x),update(y);
}
void dfs(int x,int dep,int ret,Tag now){
if(!dep){
int ans=0;
for(int i=0;i<32;++i) ans|=now.mp(i,ret>>i&1)<<i;
for(int i=0;i<sz[x];++i) printf("%u ",ans);
return ;
}
down(x,dep);
if(ch[x][0]) dfs(ch[x][0],dep-1,ret,now);
if(ch[x][1]) dfs(ch[x][1],dep-1,ret|(1<<dep-1),now);
}
}
namespace Treap{
int rt,cnt;
int ch[N*15][2],sz[N*15],rnd[N*15],l[N*15],r[N*15],tr[N*15];
Tag val[N*15],lzy[N*15];
inline void update(int p){
sz[p]=1+sz[ch[p][0]]+sz[ch[p][1]];
}
inline void down(int p){
val[ch[p][0]]*=lzy[p]; val[ch[p][1]]*=lzy[p];
lzy[ch[p][0]]*=lzy[p]; lzy[ch[p][1]]*=lzy[p];
lzy[p]=Tag();
}
inline void split(int p,int k,int &x,int &y){
if(!p) return x=y=0,void();
down(p);
if(sz[ch[p][0]]>=k) split(ch[p][0],k,x,ch[p][0]),y=p,update(p);
else split(ch[p][1],k-sz[ch[p][0]]-1,ch[p][1],y),x=p,update(p);
}
inline int merge(int x,int y){
if(!x||!y) return x|y;
if(rnd[x]>rnd[y]) return down(x),ch[x][1]=merge(ch[x][1],y),update(x),x;
else return down(y),ch[y][0]=merge(x,ch[y][0]),update(y),y;
}
inline int Rank(int p,int k,int ret=0){
while(p){
down(p);
if(r[p]<=k) ret+=sz[ch[p][0]]+1,p=ch[p][1];
else p=ch[p][0];
}
return ret;
}
inline void cut(int k){
int a,b;
split(rt,Rank(rt,k),rt,a);
if(!a) return ;
split(a,1,a,b);
if(l[a]==k+1) return rt=merge(rt,merge(a,b)),void();
int c=++cnt,d=++cnt,num=k-l[a]+1; val[c]=val[d]=val[a]; sz[c]=sz[d]=1;
rnd[c]=rand(); rnd[d]=rand();
Trie::split(tr[a],num,32,tr[c],tr[d]);
l[c]=l[a]; r[c]=k; l[d]=k+1; r[d]=r[a];
rt=merge(rt,merge(merge(c,d),b));
}
inline void Split(int L,int R,int &a,int &b,int &c){
cut(L-1); cut(R);
split(rt,Rank(rt,L-1),a,b);
split(b,Rank(b,R),b,c);
}
void dfs(int x,int h){
down(x);
Trie::lzy[tr[x]]*=val[x];
tr[h]=Trie::merge(tr[h],tr[x],32);
if(ch[x][0]) dfs(ch[x][0],h);
if(ch[x][1]) dfs(ch[x][1],h);
}
}
inline int read(register int x=0,register char ch=getchar()){
for(;!isdigit(ch);ch=getchar()) ;
for(; isdigit(ch);ch=getchar()) x=(x<<1)+(x<<3)+(ch^48);
return x;
}
int main(){
freopen("sort.in","r",stdin);
freopen("sort.out","w",stdout);
n=read(); m=read();
for(int i=1;i<=n;++i){
a[i]=read(); ++Treap::cnt;
Treap::l[i]=i; Treap::r[i]=i; Treap::sz[i]=1; Treap::rnd[i]=rand();
Treap::tr[i]=++Trie::cnt; Trie::insert(Treap::tr[i],a[i]);
Treap::rt=Treap::merge(Treap::rt,i);
}
for(int i=1,opt,l,r,x;i<=m;++i){
opt=read(); l=read(); r=read();
if(opt==1){
x=read(); int a,b,c; Tag now=Tag();
Treap::Split(l,r,a,b,c); now.A=-1; now.B=x; now.C=0;
Treap::lzy[b]*=now; Treap::val[b]*=now;
Treap::rt=Treap::merge(Treap::merge(a,b),c);
}
else if(opt==2){
x=read(); int a,b,c; Tag now=Tag();
Treap::Split(l,r,a,b,c); now.A=x; now.B=0; now.C=0;
Treap::lzy[b]*=now; Treap::val[b]*=now;
Treap::rt=Treap::merge(Treap::merge(a,b),c);
}
else if(opt==3){
x=read(); int a,b,c; Tag now=Tag();
Treap::Split(l,r,a,b,c); now.A=-1; now.B=0; now.C=x;
Treap::lzy[b]*=now; Treap::val[b]*=now;
Treap::rt=Treap::merge(Treap::merge(a,b),c);
}
else{
int a,b,c,d;
Treap::Split(l,r,a,b,c); d=++Treap::cnt; Treap::rnd[d]=rand();
Treap::sz[d]=1; Treap::l[d]=l; Treap::r[d]=r; Treap::dfs(b,d);
Treap::rt=Treap::merge(Treap::merge(a,d),c);
}
}
while(Treap::rt){
int x; Treap::split(Treap::rt,1,x,Treap::rt);
Trie::dfs(Treap::tr[x],32,0,Treap::val[x]);
}
return puts(""),0;
}
以上是关于多校第十二场 题解的主要内容,如果未能解决你的问题,请参考以下文章
HDU6602 Longest Subarray hdu多校第二场 线段树
[2020HDU多校第二场][HDU 6770][H. Dynamic Convex Hull]
2021年软件类第十二届蓝桥杯第二场省赛 python组 F-J题解