mint dfs2(int u, int fa, int sz/*联通块总大小*/, int d){ vis[u] = false; mint r = 0; mint pre = sz - siz[u] + 1; // 父方向 节点数 包括u; 树上换根 + 前缀和dp r += pre; for(auto v : G[u]) if(v!=fa && a[v]%d==0){ r += pre * siz[v]; // 当前v级子树的点和 前面点覆盖了u的路径数 pre += siz[v]; r += dfs2(v, u, sz, d); } return r; }
int phi[N+10]; // phi(i) intmain(){ { // calc phi iota(phi,phi+N+1,0); vector<bool> p(N+1,0); // prime vis rep(i,2,N+1) if(!p[i]) for(int j=i;j<=N;j+=i){ // j = ki p[j] = true; (phi[j] /= i) *= (i-1); } } int n = read(); { vector<vector<int>>ys(N+1); // ys[i] = {i的因数} rep(i,1,N+1) for(int j=i;j<=N;j+=i) ys[j].push_back(i); // 计算因子 rep(i,0,n) { a[i] = read(); // 0-index for(auto x:ys[a[i]]) ys2i[x].push_back(i); } rep(i,1,n){ int u = read()-1; int v = read()-1; G[u].push_back(v); G[v].push_back(u); } } mint ans = 0; rep(d,1,N+1){ // \phi(d) * 路径上全是d的倍数的路径长度和 = \phi(d) * sum(每个点被边覆盖的次数) mint r = 0; for(auto u:ys2i[d]) if(!vis[u]) dfs1(u,u,d); for(auto u:ys2i[d]) if(vis[u]) r += dfs2(u,u,siz[u],d); ans += phi[d] * r; } rep(i,0,n) ans -= a[i]; // 去掉单点 printf("%d\n", ans.val()); return0; }
Ex - Beautiful Subsequences
给 1-N的排列p 和 k
问有多少区间[l..r]
max(p[l..r])-min(p[l..r]) <= r-l+k
范围
n 1.4e5
k [0..3]
6s
1024mb
我的思路
k很小
k=0 时的意义就是 [l..r]对应的值也是连续的一段
就是连续段计数问题
这个用 单调栈 + 线段树
到r时, 点l表示 l..r的情况
= max(a[l]..a[r]) - min(a[l]..a[r]) + l - r
所以初始化, 所有 点=l
每次r移动, 等价于全部-1
max 用单调递减栈维护, 对多个连续区间的max 做增量运算, (不要修改, 因为修改没法维护最小值
voidadd(int o, int l,int r,int ql,int qr,int v){ if (ql <= l && r <= qr) returnrange_add(o,v); down(o); if (ql<=mid) add(SEG_L_CHILD,ql,qr,v); if (qr> mid) add(SEG_R_CHILD,ql,qr,v); tie(t[o].min,t[o].cnt) = merge({t[SEG_L].min,t[SEG_L].cnt},{t[SEG_R].min,t[SEG_R].cnt}); }
pair<int,array<int,K>> query(int o,int l,int r,int ql,int qr){ // {min, count array} if (ql <= l && r <= qr) return {t[o].min,t[o].cnt}; down(o); auto ret = pair(0,array<int,K>{0,0,0,0}); // {min, count array} if (ql<=mid) ret = merge(ret,query(SEG_L_CHILD,ql,qr)); if (qr> mid) ret = merge(ret,query(SEG_R_CHILD,ql,qr)); return ret; }
intmain(){ int n = read(); int k = read(); rep(i,0,n) a[i] = read();