20260923 每日 2.0 2.5 4.0

No.2409 Strange Werewolves

是0的那个必须留到最后,所以剩下的选法就是 $(X + Y - Z - 1)!$

然后考虑剩下的 Z 个和 最后剩下那个,选法就是 $\binom{X}{Z} \times Y$

当然如果不是 W 是 0 的话,swap 一下就行

No.1596 Distance Sum in 2D Plane (2D平面上距离和)

首先是经典的如何算无约束下的结果,就是 从 2N 中方案里选择 N 步向上,也就是 $\binom{2N}{N} \times 2N$ 元。

然后遇到约束的时候考虑,经过该路径的路径价格 -= 1 就可以了

横着的就是 $\binom{x+y}{x} \times \binom{2 N -x-y-1}{N-y}$

竖着的就是 $\binom{x+y}{x} \times \binom{2 N -x-y-1}{N-x}$

No.2340 Triple Tree Query(EASY)

https://yukicoder.me/problems/no/2340

考虑简化成区间修改 + 单点查询的问题,设 运算 $F(x, c, d) := cx + d$

满足结合律且有单位元,所以可以用线段树来维护,于是考虑如何维护后代区间关系。

因为 K = 1,于是可以考虑子代和父亲单独维护一个区间,使用时间计数即可。

在计数过程中,搜索顺序是 先搜到一端的叶子再搜另一端,于是有搜索:

auto dfs = [&](this auto && dfs, int u, int f) -> void {
  		fa[u] = f;
  		L[u] = tt + 1;
  		for(auto v : e[u]) if(v != f) {
				pos[v] = ++ tt;  			
  		}
  		H[u] = tt;
  		for(auto v : e[u]) if(v != f) {
  			dfs(v, u);
  		}
  		R[u] = tt;
  	};

H[i] 维护的是 K = 1 时候的可选集合, R[i] 则是子树时的。

这题也可以使用 BFS 来做,但是要用栈。

后续的区间修改单点查询不一定非要使用Lazy Segtree,可以考虑用 Dual Segt

namespace XK {

template <typename T>
struct dual_segment_tree{
  int N;
  vector<T> ST;
  function<T(T, T)> f;
  T E;
  dual_segment_tree(int n, function<T(T, T)> f, T E): f(f), E(E){
    N = 1;
    while (N < n){
      N *= 2;
    }
    ST = vector<T>(N * 2 - 1, E);
  }
  void push(int i){
    if (i < N - 1){
      ST[i * 2 + 1] = f(ST[i * 2 + 1], ST[i]);
      ST[i * 2 + 2] = f(ST[i * 2 + 2], ST[i]);
      ST[i] = E;
    }
  }
  T operator [](int k){
    int v = 0;
    for (int i = N / 2; i >= 1; i >>= 1){
      push(v);
      if ((k & i) == 0){
        v = v * 2 + 1;
      } else {
        v = v * 2 + 2;
      }
    }
    return ST[v];
  }
  void range_apply(int L, int R, T x, int i, int l, int r){
    if (r <= L || R <= l){
    } else if (L <= l && r <= R){
      ST[i] = f(ST[i], x);
    } else {
      push(i);
      int m = (l + r) / 2;
      range_apply(L, R, x, i * 2 + 1, l, m);
      range_apply(L, R, x, i * 2 + 2, m, r);
    }
  }
  void range_apply(int L, int R, T x){
    range_apply(L, R, x, 0, 0, N);
  }
};
const ll mod = 998244353;
struct mm {
};

using pmm = pair<mm, mm>;

pmm comp(pmm a, pmm b) {
	return {
		a.fst * b.fst,
		a.snd * b.fst + b.snd
	};
}

  void solve() {
  	int N, Q; cin >> N >> Q;
  	V<V<int>> e(N);
  	rep(i, N - 1) {
  		int u, v; cin >> u >> v; -- u, -- v;
  		e[u].pb(v), e[v].pb(u);
  	}
  	V<int> X(N);
  	rep(i, N) cin >> X[i];

  	V<int> pos(N), fa(N, -1), L(N), R(N), H(N);
  	pos[0] = 0; 
  	int tt = 0;
  	auto dfs = [&](this auto && dfs, int u, int f) -> void {
  		fa[u] = f;
  		L[u] = tt + 1;
  		for(auto v : e[u]) if(v != f) {
				pos[v] = ++ tt;  			
  		}
  		H[u] = tt;
  		for(auto v : e[u]) if(v != f) {
  			dfs(v, u);
  		}
  		R[u] = tt;
  	};
  	dfs(0, -1);

  	dual_segment_tree<pmm> Segt(N, comp, pmm{mm(1), mm(0)});

  	rep(_, Q) {
  		int op; cin >> op;
  		if(op == 1) {
  			int V; cin >> V; -- V;
  			auto [a, b] = Segt[pos[V]];
  			cout << (a * X[V] + b).x << '\n';

  		} else if(op == 2) {
  			int V, K, C, D; cin >> V >> K >> C >> D; -- V;
  			pmm up{mm(C), mm(D)};
  			Segt.range_apply(pos[V], pos[V] + 1, up);
  			if(fa[V] != -1) Segt.range_apply(pos[fa[V]], pos[fa[V]] + 1, up);
  			if(L[V] <= H[V]) Segt.range_apply(L[V], H[V] + 1, up);

  		} else {
  			int V, C, D; cin >> V >> C >> D; -- V;
  			pmm up{mm(C), mm(D)};
  			Segt.range_apply(pos[V], pos[V] + 1, up);
  			if(L[V] <= R[V]) Segt.range_apply(L[V], R[V] + 1, up);
  		}
  	}
  }
};