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;
}