概念

  • 性质1:中序便利后为原串顺序
  • 性质2:类大(小)根堆

魔板(构树)

int Build() {
	int tp=0;
	for(int i=1;i<=n;i++) {
		son[i][0]=son[i][1]=0;
		while(tp&&h[i]<h[st[tp]]) {
			son[i][0]=st[tp--];
		}
		if(tp) son[st[tp]][1]=i;
		st[++tp]=i;
	}
	return st[1];    //返回根
}

直方图中最大的矩形

  • 思路:(小根)一个点的子树即为以它往两端延伸的所有值小于它的点集

RMQ相似序列

  • 思路:两个相似相当于笛卡尔树形态一致。
    然后我们要做一个模型转换:因为笛卡尔树的形态跟大小关系有关
    p[i]=p[j]的概率为1=0
    所以p[i]<p[j]p[i]>p[j]的概率等分为12
    因此转换为:**1-n排列笛卡尔树形态为A笛卡尔树的概率。
    对于一个子树它的跟是确定为:sizei,而它的左右子树都是两个子问题。
    而一个点的贡献值为[0,1]所以每个点的期望贡献值为 12 ,所以总贡献值为n2
    所以期望i=1n1sizein2

字符串排序

  • 思路:按位从高位到低位,找到最高为p[i]=0,所以我们可以知道[0,i1][i,n1]的大小关系。然后两个区间也是两个子问题,因此递归处理。
    当然以上只是脑中思。我们先按p[]建笛卡尔树(小根),一个节点左边代表修改前,该点表示刚修改,右边代表修改后(完美利用笛卡尔树的性质1)。
    我们先按先左后右,将每个字符挂在叶子上。
    我们再按实际大小关系走(每个点先走小的)。到叶节点标记它的rank。
  • 代码:
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N=2e6+5;
    int inf=0x3f3f3f3f,n,flag,Time,son[N][2],tp,st[N];
    ll ans=0,e=10000019,md=1e9+7,pw[N],c[N],p[N],d[N];
    int Build() {
    	tp=0;
    	for(int i=1;i<=n;i++) {
    		son[i][0]=son[i][1]=0;
    		while(tp&&p[i]<p[st[tp]]) son[i][0]=st[tp--];
    		if(tp) son[st[tp]][1]=i;
    		st[++tp]=i;
    	}
    	return st[1];
    }
    void dfs1(int u) {
    	int ls=son[u][0],rs=son[u][1];
    //	printf("!%d %d %d\n",u,ls,rs);
    	if(ls)dfs1(ls); else son[u][0]=++Time;
    	if(rs)dfs1(rs); else son[u][1]=++Time;
    }
    void dfs2(int u) {
    	if(u>n) {ans=(ans+pw[u-n-1]*flag%md)%md;flag++;return;}
    	int ls=son[u][0],rs=son[u][1];
    	if(p[u]==inf||p[u]%10<=d[u]) {
    		dfs2(ls),dfs2(rs);
    	}
    	else {
    		dfs2(rs),dfs2(ls);
    	}
    }
    int main() {
    	int T;
    	scanf("%d",&T);
    	pw[0]=1;
    	for(int i=1;i<=2e6;i++) pw[i]=pw[i-1]*e%md;
    	while(T--) {
    		flag=ans=0;
    		ll seed,a,b,mod;
    		scanf("%d",&n); Time=n;
    		scanf("%lld%lld%lld%lld",&seed,&a,&b,&mod);
    		for(int i = 0; i < n; ++i) c[i] = i;
    		for(int i = 1; i < n; ++i) {
    		    swap(c[i], c[seed%(i+1)]);
    		    seed = (seed * a + b)%mod;
    		}
    		scanf("%lld%lld%lld%lld",&seed,&a,&b,&mod);
    		for(int i = 0; i < n; ++i) {
    		    d[i+1] = seed%10;
    		    seed = (seed * a + b)%mod;
    		}
    		for(int i=1;i<=n;i++) {
    			p[i]=c[i-1];
    			if(p[i]%10==d[i]) p[i]=inf;
    		}
    //		for(int i=1;i<=n;i++) printf("%d ",p[i]);
    //		puts("");
    //		for(int i=1;i<=n;i++) printf("%d ",d[i]);
    //		puts("");
    		int rt=Build();
    		dfs1(rt);
    		dfs2(rt);
    		printf("%lld\n",ans);
    	}
    }