题目链接:【已去世】
T1 送你一个DAG
题目描述:给定一个DAG,求所有$1$到$i$的路径的长度的$k$次方之和$mathrm{mod} 998244353$.
数据范围:$nleq 10^5,mleq 2*10^5,kleq 500$
使用第二类斯特林数的通常幂转下降幂,可以转化为对于$i$求$sum inom{l}{j}$,其中$0leq jleq k$,使用组合数的递推公式$inom{n}{m}=inom{n-1}{m}+inom{n-1}{m-1}$可以dp计算。
时间复杂度$O(mk)$。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 #define Rint register int 3 using namespace std; 4 typedef long long LL; 5 const int N = 100003, M = 200003, K = 503, mod = 998244353; 6 int n, m, k, dp[N][K], fac[N], head[N], to[M], nxt[M], S[K][K]; 7 inline void add(int a, int b){ 8 static int cnt = 0; 9 to[++ cnt] = b; nxt[cnt] = head[a]; head[a] = cnt; 10 } 11 inline void upd(int &a, int b){a += b; if(a >= mod) a -= mod;} 12 int que[N], front, rear, d[N]; 13 int main(){ 14 scanf("%d%d%d", &n, &m, &k); 15 for(Rint i = 1;i <= m;i ++){ 16 int u, v; 17 scanf("%d%d", &u, &v); 18 add(u, v); ++ d[v]; 19 } 20 S[0][0] = 1; 21 for(Rint i = 1;i <= k;i ++) 22 for(Rint j = 1;j <= i;j ++) 23 S[i][j] = (S[i - 1][j - 1] + 1ll * j * S[i - 1][j]) % mod; 24 fac[0] = 1; 25 for(Rint i = 1;i <= k;i ++) fac[i] = 1ll * fac[i - 1] * i % mod; 26 front = rear = 1; 27 for(Rint i = 1;i <= n;i ++) 28 if(!d[i]) que[rear ++] = i, dp[i][0] = 1; 29 while(front < rear){ 30 int now = que[front ++]; 31 for(Rint i = head[now];i;i = nxt[i]){ 32 -- d[to[i]]; 33 if(!d[to[i]]) que[rear ++] = to[i]; 34 upd(dp[to[i]][0], dp[now][0]); 35 for(Rint j = 1;j <= k;j ++){ 36 upd(dp[to[i]][j], dp[now][j]); 37 upd(dp[to[i]][j], dp[now][j - 1]); 38 } 39 } 40 } 41 for(Rint i = 1;i <= n;i ++){ 42 int ans = 0; 43 for(Rint j = 0;j <= k;j ++) upd(ans, 1ll * fac[j] * S[k][j] % mod * dp[i][j] % mod); 44 printf("%d ", ans); 45 } 46 }
1 #include<bits/stdc++.h> 2 #define Rint register int 3 using namespace std; 4 typedef long long LL; 5 const int N = 100003, M = 200003, K = 503, mod = 998244353; 6 int n, m, k, dp[N][K], fac[N], head[N], to[M], nxt[M], S[K][K]; 7 inline void add(int a, int b){ 8 static int cnt = 0; 9 to[++ cnt] = b; nxt[cnt] = head[a]; head[a] = cnt; 10 } 11 inline void upd(int &a, int b){a += b; if(a >= mod) a -= mod;} 12 int que[N], front, rear, d[N]; 13 int main(){ 14 scanf("%d%d%d", &n, &m, &k); 15 for(Rint i = 1;i <= m;i ++){ 16 int u, v; 17 scanf("%d%d", &u, &v); 18 add(u, v); ++ d[v]; 19 } 20 S[0][0] = 1; 21 for(Rint i = 1;i <= k;i ++) 22 for(Rint j = 1;j <= i;j ++) 23 S[i][j] = (S[i - 1][j - 1] + 1ll * j * S[i - 1][j]) % mod; 24 fac[0] = 1; 25 for(Rint i = 1;i <= k;i ++) fac[i] = 1ll * fac[i - 1] * i % mod; 26 front = rear = 1; 27 for(Rint i = 1;i <= n;i ++) 28 if(!d[i]) que[rear ++] = i, dp[i][0] = 1; 29 while(front < rear){ 30 int now = que[front ++]; 31 for(Rint i = head[now];i;i = nxt[i]){ 32 -- d[to[i]]; 33 if(!d[to[i]]) que[rear ++] = to[i]; 34 upd(dp[to[i]][0], dp[now][0]); 35 for(Rint j = 1;j <= k;j ++){ 36 upd(dp[to[i]][j], dp[now][j]); 37 upd(dp[to[i]][j], dp[now][j - 1]); 38 } 39 } 40 } 41 for(Rint i = 1;i <= n;i ++){ 42 int ans = 0; 43 for(Rint j = 0;j <= k;j ++) upd(ans, 1ll * fac[j] * S[k][j] % mod * dp[i][j] % mod); 44 printf("%d ", ans); 45 } 46 }T1
T2 送你一棵圣诞树
题目描述:给定一棵点带色的树,支持修改单点颜色,查询子树颜色在$[l,r]$中的数量(相同的只算一个),强制在线。
数据范围:$n,c_ileq 10^5$。
如果直接转化为在序列上做的话是一个四维偏序,时间复杂度高而且还有可能爆空间。
所以有一个套路,对于每一种颜色的点,按照dfs序排序,将每个点打上+1,将每相邻两个点的lca打上-1,这样就可以做到相同的只算一个了。
这里是注意到了子树相对于序列的区间多了一个条件,那就是询问的序列只有相离和包含关系,这样就可以去掉一维了。
使用set维护每种颜色的点,用树状数组套动态开点线段树就可以在线做三维偏序了。
hsz神仙说即使不知道这个技巧也可以使用$O(n^{frac{5}{3}})$的分块轻松跑过去(但是对于我来说就太难写了,膜膜膜)。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 #define Rint register int 3 using namespace std; 4 const int N = 100003; 5 int n, q, t, col[N], head[N], to[N << 1], nxt[N << 1], lastans; 6 inline void add(int a, int b){ 7 static int cnt = 0; 8 to[++ cnt] = b; nxt[cnt] = head[a]; head[a] = cnt; 9 } 10 int fa[N], wson[N], dep[N], siz[N]; 11 inline void dfs1(int x){ 12 siz[x] = 1; 13 for(Rint i = head[x];i;i = nxt[i]) 14 if(to[i] != fa[x]){ 15 dep[to[i]] = dep[x] + 1; 16 fa[to[i]] = x; 17 dfs1(to[i]); 18 siz[x] += siz[to[i]]; 19 if(siz[to[i]] > siz[wson[x]]) wson[x] = to[i]; 20 } 21 } 22 int dfn[N], pre[N], top[N], tim; 23 inline void dfs2(int x, int topf){ 24 dfn[x] = ++ tim; pre[tim] = x; top[x] = topf; 25 if(wson[x]) dfs2(wson[x], topf); 26 for(Rint i = head[x];i;i = nxt[i]) 27 if(to[i] != fa[x] && to[i] != wson[x]) 28 dfs2(to[i], to[i]); 29 } 30 struct cmp {inline bool operator () (int a, int b){return dfn[a] < dfn[b];}}; 31 set<int, cmp> vec[N]; 32 inline int LCA(int u, int v){ 33 while(top[u] != top[v]){ 34 if(dep[top[u]] < dep[top[v]]) swap(u, v); 35 u = fa[top[u]]; 36 } 37 return dep[u] < dep[v] ? u : v; 38 } 39 int root[N], seg[N * 150], ls[N * 150], rs[N * 150], cnt; 40 inline void change(int &x, int L, int R, int pos, int val){ 41 if(!x) x = ++ cnt; seg[x] += val; 42 if(L == R) return; 43 int mid = L + R >> 1; 44 if(pos <= mid) change(ls[x], L, mid, pos, val); 45 else change(rs[x], mid + 1, R, pos, val); 46 } 47 inline int query(int &x, int L, int R, int l, int r){ 48 if(!x || r < l) return 0; 49 if(l <= L && R <= r) return seg[x]; 50 int mid = L + R >> 1, res = 0; 51 if(l <= mid) res = query(ls[x], L, mid, l, r); 52 if(mid < r) res += query(rs[x], mid + 1, R, l, r); 53 return res; 54 } 55 inline int lowbit(int x){return x & -x;} 56 inline void change(int posx, int posy, int val){ 57 while(posx <= n){ 58 change(root[posx], 1, n, posy, val); 59 posx += lowbit(posx); 60 } 61 } 62 inline int query(int posx, int l, int r){ 63 int res = 0; 64 while(posx){ 65 res += query(root[posx], 1, n, l, r); 66 posx -= lowbit(posx); 67 } 68 return res; 69 } 70 int main(){ 71 scanf("%d%d%d", &n, &q, &t); 72 for(Rint i = 1;i <= n;i ++) 73 scanf("%d", col + i); 74 for(Rint i = 1;i < n;i ++){ 75 int a, b; 76 scanf("%d%d", &a, &b); 77 add(a, b); add(b, a); 78 } 79 dfs1(1); dfs2(1, 1); 80 for(Rint i = 1;i <= n;i ++) vec[col[i]].insert(i); 81 for(Rint i = 1;i <= n;i ++) 82 for(set<int, cmp> :: iterator it = vec[i].begin();it != vec[i].end();it ++){ 83 change(i, dfn[*it], 1); 84 if(next(it) != vec[i].end()) change(i, dfn[LCA(*it, *next(it))], -1); 85 } 86 while(q --){ 87 int opt, u, x, y; 88 scanf("%d%d%d", &opt, &u, &x); 89 if(t) u ^= lastans, x ^= lastans; 90 if(opt == 1){ 91 scanf("%d", &y); if(t) y ^= lastans; 92 printf("%d ", lastans = query(y, dfn[u], dfn[u] + siz[u] - 1) - query(x - 1, dfn[u], dfn[u] + siz[u] - 1)); 93 } else { 94 set<int, cmp> :: iterator it = vec[col[u]].find(u); 95 change(col[u], dfn[u], -1); 96 if(it != vec[col[u]].begin()) change(col[u], dfn[LCA(*it, *prev(it))], 1); 97 if(next(it) != vec[col[u]].end()) change(col[u], dfn[LCA(*it, *next(it))], 1); 98 if(it != vec[col[u]].begin() && next(it) != vec[col[u]].end()) 99 change(col[u], dfn[LCA(*prev(it), *next(it))], -1); 100 vec[col[u]].erase(it); col[u] = x; 101 it = vec[x].insert(u).first; 102 if(it != vec[x].begin()) change(x, dfn[LCA(*prev(it), *it)], -1); 103 if(next(it) != vec[x].end()) change(x, dfn[LCA(*it, *next(it))], -1); 104 if(it != vec[x].begin() && next(it) != vec[x].end()) 105 change(x, dfn[LCA(*prev(it), *next(it))], 1); 106 change(x, dfn[u], 1); 107 } 108 } 109 }
T3 送你一棵圣诞树
神仙题,咕咕咕。。。