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})\) 对点,而其中大部分是没用的,优化方式有两种:
- 对于 LCA \(u\),其不同子树中点 \(a<b<c\),那么点对 \((a,c)\) 就是无用的,其可以被 \((a,b)\) 完全替代。启发式合并
set
维护子树中的点,每个点找前驱后继做贡献即可 - 考虑扫描线扫到 \(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;
}