20220617

  • rk 9/53, 100+25+100=225
  • max: 100+100+100=300

思考很混乱,一些显然的东西没有想到。不过运气很好
T1 一直在想奇怪的东西,盯着式子看了一会发现不需要维护生成函数的系数,代值进去就行了
T3 会了 \(O(n^{2}\log n)\) 后一直在想如何快速增量,结果确实可以维护


sign

写出每个点的 OGF,发现不需要维护系数,带入 \(son_u\) 求值即可。不同的 \(son_u\) 只有根号种,对每种统一计算答案,使用光速幂去 \(\log\)。时间复杂度 \(O(\sqrt{n}(n+\sqrt{mod}))\)
注意特判 \(son_u=1\)

考场代码

实现的很粗糙,但很短

const int N = 1e5+5;
int n,fa[N],a[N];
LL inv[N];
Vi e[N];

void sieve(int n=1e5) {
	inv[0] = inv[1] = 1; For(i,2,n) inv[i] = (mod-mod/i) * inv[mod%i] %mod;
}

LL dfs(int u,int x) {
static gp_hash_table<int,int> f[N];
	if( f[u].find(x) != f[u].end() ) return f[u][x];
	LL res = x==1 ? a[u]+1 : (Pow(x,a[u]+1)-1)*inv[x-1]%mod;
	for(int v : e[u]) (res *= dfs(v,x)) %=mod;
	return f[u][x] = res;
}

signed main() { freopen("sign.in","r",stdin); freopen("sign.out","w",stdout);
	sieve();
	io>>n; For(i,2,n) io>>fa[i], e[fa[i]].pb(i); For(i,1,n) io>>a[i];
	For(i,1,n) io<<(e[i].empty()?1:dfs(i,sz(e[i])))<<endl;
	return 0;
}

match

LG7880

扫描线,\(O(n^{2}\log n)\) 平凡。问题在于计算了 \(O(n^{2})\) 对点,而其中大部分是没用的,优化方式有两种:

  1. 对于 LCA \(u\),其不同子树中点 \(a<b<c\),那么点对 \((a,c)\) 就是无用的,其可以被 \((a,b)\) 完全替代。启发式合并 set 维护子树中的点,每个点找前驱后继做贡献即可
  2. 考虑扫描线扫到 \(r\) 时,对于 \(r\) 的祖先 \(v,fa_{v}=u\),需要在“子树 \(u\) 除了子树 \(v\) 的部分”查询最大的 \(l\) 做贡献。注意到若上一次也是在“子树 \(u\) 除了子树 \(v\) 的部分”查询 \(l\),那么这次操作就是无效的,因为 \(l\) 没有变化。记这样的 \((u,v)\) 为虚边,\(r\) 进行的操作是对于根链上的虚边,查询 \(l\) 做贡献,并改为实边。这个过程恰好是 LCT 的 access

最终得到的点对数量均为 \(O(n\log n)\),时间复杂度 \(O(n\log^{2}n+m\log n)\)

考场代码

第二种做法

const int N = 1e5+5;
int n,m,ind,fa[N],dfn[N],dfno[N],ans[N*5];
LL dis[N];
vector<Pii> e[N],q[N];

struct {
	int t[N];
	gp_hash_table<LL,int> pos;
	void add(int i,int x) { for(;i;i-=i&-i) t[i]+=x; }
	int sum(int i) { int res=0; for(;i<=n;i+=i&-i)res+=t[i]; return res; }
	void mdf(LL x,int l) { if( pos[x] < l ) add(pos[x],-1), add(pos[x]=l,1); }
} ft;

#define ls (u<<1)
#define rs (u<<1|1)
#define mid (l+r>>1)
struct {
	int t[N*4];
	void ins(int p,int x,int u=1,int l=1,int r=n) {
		ckmax(t[u],x);
		if( l == r ) return;
		p<=mid ? ins(p,x,ls,l,mid) : ins(p,x,rs,mid+1,r);
	}
	int qry(int ql,int qr,int u=1,int l=1,int r=n) {
		if( qr < l || r < ql ) return 0;
		if( ql <= l && r <= qr ) return t[u];
		return max(qry(ql,qr,ls,l,mid),qry(ql,qr,rs,mid+1,r));
	}
	void upd(int u,int r)
		{ ft.mdf(dis[u], max(qry(dfn[u],dfn[r]-1),qry(dfno[r]+1,dfno[u]))); }
} seg;
#undef ls
#undef rs
#undef mid

bool vis[N];
struct {
	struct { int fa,ch[2]; } t[N];
	#define fa(u) t[u].fa
	#define ls(u) t[u].ch[0]
	#define rs(u) t[u].ch[1]
	bool wh(int u) { return rs(fa(u))==u; }
	bool nrt(int u) { return ls(fa(u))==u||rs(fa(u))==u; }
	void rotate(int x) {
		int y = fa(x), z = fa(y), k = wh(x), w = t[x].ch[!k];
		if( nrt(y) ) t[z].ch[wh(y)] = x; t[x].ch[!k] = y, t[y].ch[k] =w; 
		fa(w) = y, fa(y) = x, fa(x) = z;
	}
	void splay(int u) {
		for(; nrt(u); rotate(u))
			if( nrt(fa(u)) ) rotate(wh(fa(u))==wh(u)?fa(u):u);
	}
	int top(int u) { while( ls(u) ) u = ls(u); return splay(u), u; }
	void access(int x) {
		for(int u = x, v = 0; u; u = fa(v=u))
			splay(u), rs(u) = v,
			u = top(u), seg.upd(fa(u),u);
		splay(x);
	}
	#undef fa
	#undef ls
	#undef rs
} lct;

#define v i.fi
void dfs(int u,int fa) {
	dfn[u] = ++ind;
	for(auto &i : e[u]) if( v != fa )
		lct.t[v].fa = u, dis[v] = dis[u]+i.se, dfs(v,u);
	dfno[u] = ind;
}
#undef v

signed main() { freopen("tree.in","r",stdin); freopen("tree.out","w",stdout);
	io>>n>>m; Rep(i,1,n, x,y,z) io>>x>>y>>z, e[x].pb(y,z), e[y].pb(x,z);
	For(i,1,m, l,r) io>>l>>r, q[r].pb(i,l);
	dfs(1,0);
	For(i,1,n) {
		lct.access(i), ft.mdf(dis[i],i);
		seg.ins(dfn[i],i);
		for(auto &j : q[i]) ans[j.fi] = ft.sum(j.se);
	}
	For(i,1,m) io<<ans[i]<<endl;
	return 0;
}
posted @ 2022-06-20 07:00  401rk8  阅读(30)  评论(0编辑  收藏  举报