年终做题记录

(模板)后缀树

namespace SufT {
	int ch[N<<1][29],link[N<<1],st[N<<1],len[N<<1],now,rem,cnt,sz;
	void init() {cnt=1,now=1,len[0]=inf;}
	int nw(int s,int l) {st[++cnt]=s,len[cnt]=l,link[cnt]=1; return cnt;}
	void extend(int x) {
		sz++, rem++; int last=1;
		while(rem) {
			while(rem>len[ch[now][s[sz-rem+1]]]) rem-=len[now=ch[now][s[sz-rem+1]]];
			int &v=ch[now][s[sz-rem+1]], c=s[st[v]+rem-1];
			if(x==c||!v) {
				link[last]=now,last=now;
				if(!v) v=nw(sz-rem+1,inf); else break;
			} else {
				int u=nw(st[v],rem-1);
				ch[u][c]=v, ch[u][x]=nw(sz,inf);
				st[v]+=rem-1, len[v]-=rem-1;
				link[last]=v=u, last=u;
			}
			if(now==1) rem--; else now=link[now];
		}
	}
	void creal() {
		rep(i,1,cnt) if(len[i]>n) len[i]=n-st[i]+1;
	}
	int dfs(int u,int dep,int lf=1,int res=0) {
		rep(i,0,26) if(ch[u][i]) {
			int v=ch[u][i]; res+=dfs(v,dep+len[v]); lf=0;
		}
		if(res>1) ans=max(ans,1ll*res*dep);
		else if(lf) res=1;
		return res;
	}
}

(模板)广义后缀树

https://www.luogu.com.cn/record/64216308

LG4198 楼房重建

全部化成斜率形式。

考虑线段树维护区间最大值 \(g_{[l,r]}\) 和区间答案 \(s_{[l,r]}\),其中区间答案为只提取这个区间,从区间左端点向右边看,能看到区间内的楼房数。

由于题目只有单点修改,所以我们唯一的问题在于如何 push up。

显然 \(g\) 是容易 push up 的,考虑 \(s\)\(s\) 的结构比较特殊,导致其无法直接根据儿子节点算出。考虑在 pushup 的时候 \(O(\log n)\) 时间在子树中求解。

(设 \(ls\) 为左儿子,\(rs\) 为右儿子)假如我们现在在计算 \(s_u\) 的值。首先 \(s_{ls_u}\) 必然包括在 \(s_u\) 里面。我们递归处理右儿子子树中的情况:

  • 设目前递归区间 \([l,r]\) (线段树上节点为 \(v\)
  • 如果 \(g_{ls_v}<g_{ls_u}\),则 \(s_{ls_v}\) 不会被包含在 \(s_u\) 中,直接递归 \(rs_v\)
  • 如果 \(g_{ls_v}>g_{ls_u}\),则 \(s_{rs_v}\) 被包含在 \(s_v\) 中的那部分会有解,即对 \(s_u\) 的贡献为 \(s_v-s_{ls_v}\)。然后递归 \(ls_v\)

https://hydro.ac/d/bzoj/record/61b40273b6d37bd6e20ce252

https://www.luogu.com.cn/record/64730443

BZOJ2588 Count on a tree

树上主席树

主席树需要维护的东西具有可减性。树上 \(u,v\) 路径为 \(s_u+s_v-s_{lca}-s_{fa_{lca}}\)

然后每个节点的主席树可以从父节点继承过来修改。

https://www.luogu.com.cn/record/64958724

https://hydro.ac/d/bzoj/record/61b732bae2b0fa8e2f76c97b

SDOI2013 森林

考虑如何处理合并。可以启发式处理树的合并,因为只需要维护倍增数组和修改主席树即可。

https://www.luogu.com.cn/record/64866325

LG7706 「Wdsr-2.7」文文的摄影布置

考虑线段树维护区间的 \(s_i\) 表示在该区间内的答案。考虑如何合并。

  • 取左区间的 \(s\) 或者右区间的 \(s\)\(s\leftarrow \max(s_{l_i},s_{r_i})\)
  • 取左区间的 \(i,j\) 右区间的 \(k\) 或左区间的 \(i\) 右区间的 \(j,k\)。维护 \(m_i\) 表示区间最大 \(a\)\(n_i\) 表示区间最小 \(b\)\(g_i\) 表示区间最大 \(a_p-b_q(p<q)\)\(h_i\) 表示区间最大 \(a_p-b_q(p>q)\),则有 \(s\leftarrow \max(g_{l_i}+m_{r_i},m_{l_i}+h_{r_i})\)\(g_i=\max(g_{l_i},g_{r_i},m_{l_i}-n_{r_i})\)\(h_i=\max(h_{l_i},h_{r_i},m_{r_i}-n_{l_i})\)

https://www.luogu.com.cn/record/64972767

LG5278 算术天才⑨与等差数列

形成差为 \(k\) 的等差数列相当于要满足以下条件:

  • \(\max-\min=k(r-l)\)
  • 区间的差分数组的 \(\gcd\)\(k\)
  • 区间内的数互不相同

第一个条件可以用线段树维护区间最大/小值,第二个条件可以用线段树维护差分数组的 \(\gcd\),第三个条件先用一个 set 维护每个数前一个与自己相等的数 \(p\),然后 \(p\) 放到线段树上维护,条件相当于区间 \(p\)\(\max\)\(<l\)

注意:\(set\) 一定要用自带的 lowerbound 否则会 t!

还有求 \(n\) 个数的 \(\gcd\) 是均摊 \(O(n+\log v)\) 的,于是单点修区间 \(\gcd\)\(O(n(\log n+\log v))\) 的。

https://www.luogu.com.cn/record/65080182

POI2015 LOG-Logistyka

一个美妙的结论。考虑转换“每次选出 \(c\) 个数 \(-1\) 并能选 \(s\) 次”这个条件。

我们相当于把这些数填一个 \(s\times c\) 的矩阵并且每行不同。考虑把数分为 \(\ge s\)\(<s\) 的两种数。\(\ge s\)\(k\) 个数最多直接填满 \(k\) 列,剩下的数可以直接从上往下摊,即出现次数 \(<s\) 的数的总和要 \(\ge s\times (c-k)\)

https://www.luogu.com.cn/record/65201956

POI2011 ROZ-Difference

考虑枚举最多的字符 \(a\) 和最少的字符 \(b\),归并起来得到一个长 \(a+b\)\(\pm 1\) 序列(\(a\)\(1\)\(b\)\(-1\)),我们求出包含 \(-1\) 的最大连续子序列即可。对于得到的一个极大值,如果其不含 \(-1\),在其两边找 \(-1\) 即可。

https://loj.ac/s/1325069

HNOI2015 开店

点分树。目前还不是特别理解,但是主体思想是根据点分治建出重心分治树,然后对于一个问询就暴力跳来得到各个子树答案之和,至于如何计算和换根有一定相似之处。

https://loj.ac/s/1327497

LG4178 Tree (点分治模板)

给定带权树,问距离 \(\le k\) 的点对数。

套路化地,可以分为以下几个函数:

  • 找重心
    • 注意找 \(v\) 子树重心时,需要记录当前连通块 \(sz\) 要设为 \(sz_v\)
    • 找重心时 size 要重算
  • 统计信息
    • 定义点分树上的点 \(p\) 的点分数上子树 \(S_p\) ,其点分树上的父节点 \(fa_p\),则统计操作实则为统计 \(S_u\) 内部的信息。
    • 实际上统计由于是统计原树,所以实际上是在原树上搜索 \(S\) 所代表的连通块来得到答案。点分树上子树必然代表原树上的一个等价连通块,点分树上子树包含关系相当于原树上的连通块包含关系。所以,本质上就是将树在 \(O(\log n)\) 层内分治为 \(size\) 之和为 \(O(n\log n)\) 的连通块。
  • 遍历/建树
    • 建立点分树。具体操作为在建立 \(u\) 的点分树子树时先进行统计,然后再往下建树。

这题合并分治的过程可以维护一个树状数组,然后求解即可。

https://www.luogu.com.cn/record/65628431

CQOI2015 选数

\(l=\lfloor \frac{L}{k}\rfloor\)\(r=\lfloor\frac{H}{k}\rfloor\)\(p(x)=\lfloor\frac{r}{x}\rfloor-\lfloor\frac{l-1}{x}\rfloor\)(代表 \([l,r]\)\(x\) 倍数的个数)

我们相当于要计算 \([l,r]\) 选数的最大公因数为 \(1\) 的方案数。我们发现对于 \(d>r-l\)\(d\) 的倍数最多在 \(r-l\) 中出现一次,而出现超过一次的 \(d\) 倍数的 \(d\) 的个数是 \(O(H-L)\) 的,所以我们考虑避掉 \(d>r-l\) 的统计。

我们发现如果要是 \(d>r-l\) 的倍数,那么必须全部相等。所以我们设 \(f(x)\) 表示 \(\gcd\)\(x\) 且不全相等的方案数。\(f(x)=p(x)^n-p(x)-\sum_{x|y}f(y)\),倒着统计即可,复杂度 \(O((H-L)\log (H-L))\)

https://loj.ac/s/1329439

CQOI2015 网络吞吐量

最短路+网络流(点限制->拆点)的清新小模板。

注意! dijkstra 松弛的时候务必注意不能取等,不然会假。

https://loj.ac/s/1329480

LG3806 【模板】点分治

先把询问离线下来,然后在处理 \(u\) 点的时候,把询问全部做了,复杂度 \(O(n\log^2n+nm\log n)\)

https://www.luogu.com.cn/record/65712878

IOI2011 Race

对于分治子块时,我们还是可以维护一个桶,然后算。

https://www.luogu.com.cn/record/66021072

posted @ 2022-01-01 10:38  LarsWerner  阅读(25)  评论(0编辑  收藏  举报