2021-06-19 集训题解
T1 区间第 k 小
Description
给出一个长度为 \(n\) 的序列,给出 \(w\),有 \(q\) 次查询,每次查询给出 \(l,r,k\),求出忽视掉区间出现次数 \(\ge w\) 的数之后第 \(k\) 大是多少,如没有 \(k\) 个则输出 \(n\)。
\(n\le 10^5,0\le a_i<n\)
Solution
考虑分块。我们可以先提前处理出 \(s1_{i,j,k}\) 和 \(s2_{i,j}\),\(s1_{i,j,k}\) 表示区间上第 \(i\) 个块到第 \(j\) 个块第 \(k\) 个值域块出现次数 \(\le w\) 的数的出现次数之和,\(s2_{i,j}\) 表示前面 \(i\) 个块 \(j\) 的出现次数。
然后查询的时候就可以算出每个值域块的个数,以及每个数的出现次数,用平衡树上查询第 \(k\) 大的方法查就好了。
时空复杂度均为 \(\Theta(n\sqrt n)\)。
Code
#include <bits/stdc++.h>
using namespace std;
#define Int register int
#define MAXN 100005
#define MAXM 355
template <typename T> void read (T &x){char c = getchar ();x = 0;int f = 1;while (c < '0' || c > '9') f = (c == '-' ? -1 : 1),c = getchar ();while (c >= '0' && c <= '9') x = x * 10 + c - '0',c = getchar ();x *= f;}
template <typename T,typename ... Args> void read (T &x,Args& ... args){read (x),read (args...);}
template <typename T> void write (T x){if (x < 0) x = -x,putchar ('-');if (x > 9) write (x / 10);putchar (x % 10 + '0');}
template <typename T> void chkmax (T &a,T b){a = max (a,b);}
template <typename T> void chkmin (T &a,T b){a = min (a,b);}
int n,w,T,siz,cnt,type,a[MAXN],t[MAXN],t1[MAXM],bel[MAXN],col[MAXN],cor[MAXN],s1[MAXM][MAXM][MAXM],s2[MAXM][MAXN];
void buildit (){
siz = sqrt (n),cnt = (n - 1) / siz + 1;
for (Int i = 1;i <= n;++ i) bel[i] = (i - 1) / siz + 1,cor[bel[i]] = i,col[bel[i]] = !col[bel[i]] ? i : col[bel[i]];
for (Int j = 1;j <= cnt;++ j)
for (Int i = 1;i <= cor[j];++ i)
s2[j][a[i]] ++;
for (Int i = 1;i <= cnt;++ i){
for (Int j = i;j <= cnt;++ j){
for (Int k = 1;k <= cnt;++ k) s1[i][j][k] = s1[i][j - 1][k];
for (Int k = col[j];k <= cor[j];++ k){
++ t[a[k]];
if (t[a[k]] < w) s1[i][j][bel[a[k]]] ++;
else if (t[a[k]] == w) s1[i][j][bel[a[k]]] -= w - 1;
}
}
for (Int j = 1;j <= n;++ j) t[j] = 0;
}
}
int query (int l,int r,int k){
int res = n + 1;
if (bel[l] == bel[r]){
for (Int i = 1;i <= cnt;++ i) t1[i] = 0;
for (Int i = l;i <= r;++ i){
t[a[i]] ++;
if (t[a[i]] < w) t1[bel[a[i]]] ++;
else if (t[a[i]] == w) t1[bel[a[i]]] -= w - 1;
}
for (Int i = 1;i <= cnt;++ i)
if (t1[i] >= k){
for (Int j = col[i];j <= cor[i];++ j)
if (t[j] >= w) continue;
else if (t[j] >= k){
res = j;
break;
}
else k -= t[j];
break;
}
else k -= t1[i];
for (Int i = l;i <= r;++ i) t[a[i]] --;
return res - 1;
}
int qL = bel[l],qR = bel[r];
for (Int i = 1;i <= cnt;++ i) t1[i] = s1[qL + 1][qR - 1][i];
for (Int i = l,h;i <= cor[qL];++ i){
t[a[i]] ++;
if ((h = t[a[i]] + s2[qR - 1][a[i]] - s2[qL][a[i]]) < w) t1[bel[a[i]]] ++;
else if (h == w) t1[bel[a[i]]] -= w - 1;
}
for (Int i = col[qR],h;i <= r;++ i){
t[a[i]] ++;
if ((h = t[a[i]] + s2[qR - 1][a[i]] - s2[qL][a[i]]) < w) t1[bel[a[i]]] ++;
else if (h == w) t1[bel[a[i]]] -= w - 1;
}
for (Int i = 1;i <= cnt;++ i)
if (t1[i] >= k){
for (Int j = col[i];j <= cor[i];++ j){
int h = t[j] + s2[qR - 1][j] - s2[qL][j];
if (h >= w) continue;
else if (h >= k){res = j;break;}
else k -= h;
}
break;
}
else k -= t1[i];
for (Int i = l;i <= cor[qL];++ i) t[a[i]] --;
for (Int i = col[qR];i <= r;++ i) t[a[i]] --;
return res - 1;
}
signed main(){
read (n,w,T,type),++ w;
for (Int i = 1;i <= n;++ i) read (a[i]),++ a[i];
buildit ();int lst = 0;
while (T --> 0){
int l,r,k;read (l,r,k);
l ^= lst * type,r ^= lst * type,k ^= lst * type;
write (lst = query (l,r,k)),putchar ('\n');
}
return 0;
}
T2 求和
Description
Solution
发现式子可以化成:
\[\sum_{x=1}^{n} \sum_{d=1}^{k} f_d(x)(2\sum_{i=1}^{\lfloor\frac{n}{x}\rfloor} \varphi(i)-1)
\]
前面那个可以 \(\text{Powerful Number}\) 做,后面的那个可以杜教筛。拟合函数用 \(\mu\) 就可以了。
复杂度显然是 \(\Theta(n^{2/3})\) 。
Code
#include <bits/stdc++.h>
using namespace std;
#define Int register long long
#define mod 1073741824
#define int long long
#define MAXN 5000005
template <typename T> void read (T &x){char c = getchar ();x = 0;int f = 1;while (c < '0' || c > '9') f = (c == '-' ? -1 : 1),c = getchar ();while (c >= '0' && c <= '9') x = x * 10 + c - '0',c = getchar ();x *= f;}
template <typename T,typename ... Args> void read (T &x,Args& ... args){read (x),read (args...);}
template <typename T> void write (T x){if (x < 0) x = -x,putchar ('-');if (x > 9) write (x / 10);putchar (x % 10 + '0');}
template <typename T> void chkmax (T &a,T b){a = max (a,b);}
template <typename T> void chkmin (T &a,T b){a = min (a,b);}
int mul (int a,int b){return 1ll * a * b % mod;}
int dec (int a,int b){return a >= b ? a - b : a + mod - b;}
int add (int a,int b){return a + b >= mod ? a + b - mod : a + b;}
int qkpow (int a,int b){
int res = 1;for (;b;b >>= 1,a = mul (a,a)) if (b & 1) res = mul (res,a);
return res;
}
void Add (int &a,int b){a = add (a,b);}
int upd (int x){return x < 0 ? x + mod : x;}
#define lim 5e6
int N,K;
bool vis[MAXN];
int sq,cnt,ptot,pf[MAXN],mu[MAXN],mn[MAXN],mx[MAXN],dF[MAXN],id1[MAXN],id2[MAXN],phi[MAXN],dmu[MAXN],num[MAXN],dphi[MAXN],prem[MAXN],prep[MAXN],preF[MAXN],idsum[MAXN],prime[MAXN];
int getF (int n){
if (n == 1) return K;
if (mx[n] > K) return 0;
return mul (upd (idsum[n] & 1 ? -1 : 1),K - mx[n] + 1);
}
int getSum (int n){
if (n & 1) return mul ((n + 1) / 2 % mod,n % mod);
else return mul (n / 2 % mod,(n + 1) % mod);
}
void Euler (int up){
mu[1] = phi[1] = 1;
for (Int i = 2;i <= up;++ i){
if (!vis[i]) prime[++ ptot] = i,mx[i] = mn[i] = idsum[i] = 1,mu[i] = -1,phi[i] = i - 1;
for (Int j = 1;j <= ptot && i * prime[j] <= up;++ j){
vis[i * prime[j]] = 1,idsum[i * prime[j]] = idsum[i] + 1;
if (i % prime[j])
mx[i * prime[j]] = max (mx[i],1ll),mn[i * prime[j]] = 1,
mu[i * prime[j]] = -mu[i],phi[i * prime[j]] = phi[i] * (prime[j] - 1);
else{
mx[i * prime[j]] = max (mx[i],mn[i] + 1),mn[i * prime[j]] = mn[i] + 1;
phi[i * prime[j]] = phi[i] * prime[j];
break;
}
}
}
for (Int i = 1;i <= up;++ i) prem[i] = add (prem[i - 1],upd (mu[i])),prep[i] = add (prep[i - 1],phi[i]),preF[i] = add (preF[i - 1],getF (i));
}
int getmu (int n){
if (n <= lim) return prem[n];
int pos = n <= sq ? id1[n] : id2[N / n];
if (~dmu[pos]) return dmu[pos];
int &res = dmu[pos] = 1;
for (Int l = 2,r;l <= n;l = r + 1) r = n / (n / l),res = dec (res,mul (r - l + 1,getmu (n / l)));
return res;
}
int getphi (int n){
if (n <= lim) return prep[n];
int pos = n <= sq ? id1[n] : id2[N / n];
if (~dphi[pos]) return dphi[pos];
int &res = dphi[pos] = 1ll * n * (n + 1) / 2 % mod;
for (Int l = 2,r;l <= n;l = r + 1) r = n / (n / l),res = dec (res,mul (r - l + 1,getphi (n / l)));
return res;
}
#define inf 1e9
#define pii pair<int,int>
int tot;
pii pwer[1000005];
void dfs (int now,int n,int down,int up){
pwer[++ tot].first = n;
if (up == inf) pwer[tot].second = max (K - down,0ll) + min (down,K) / 2;
else pwer[tot].second = min (up,K) / 2;
for (Int i = now + 1;i <= ptot && n <= N / prime[i] / prime[i];++ i)
for (Int pw = prime[i] * prime[i],e = 2;n * pw <= N;pw *= prime[i],e ++){
if (e & 1) dfs (i,n * pw,down,min (up,e));
else dfs (i,n * pw,max (down,e),up);
}
}
int getf (int n){
if (n <= lim) return preF[n];
int pos = n <= sq ? id1[n] : id2[N / n];
if (~dF[pos]) return dF[pos];
int &res = dF[pos] = 0;
for (Int l = 1,r;l <= tot && num[l] <= n;l = r + 1)
r = n / (n / num[l]),
r = upper_bound (num + 1,num + tot + 1,r) - num - 1,
Add (res,mul (dec (pf[r],pf[l - 1]),getmu (n / num[l])));
return res;
}
signed main(){
read (N,K),sq = sqrt (N),Euler (min (N,(int)lim));
for (Int l = 1,r;l <= N;l = r + 1){
r = N / (N / l);
if (N / l <= sq) id1[N / l] = ++ cnt;
else id2[N / (N / l)] = ++ cnt;
}
for (Int i = 1;i <= cnt;++ i) dF[i] = dmu[i] = dphi[i] = -1;
dfs (0,1,0,inf),sort (pwer + 1,pwer + tot + 1);
for (Int i = 1;i <= tot;++ i) num[i] = pwer[i].first,pf[i] = add (pf[i - 1],pwer[i].second);
int ans = 0;
for (Int l = 1,r,lst = 0;l <= N;l = r + 1){
r = N / (N / l);int t = getphi (N / l),h = getf (r);
Add (ans,mul (dec (h,lst),dec (add (t,t),1))),lst = h;
}
write (ans),putchar ('\n');
return 0;
}
T3
Description
Solution
Code
#include <bits/stdc++.h>
using namespace std;
#define Int register int
#define MAXN 1000005
template <typename T> void read (T &x){char c = getchar ();x = 0;int f = 1;while (c < '0' || c > '9') f = (c == '-' ? -1 : 1),c = getchar ();while (c >= '0' && c <= '9') x = x * 10 + c - '0',c = getchar ();x *= f;}
template <typename T,typename ... Args> void read (T &x,Args& ... args){read (x),read (args...);}
template <typename T> void write (T x){if (x < 0) x = -x,putchar ('-');if (x > 9) write (x / 10);putchar (x % 10 + '0');}
template <typename T> void chkmax (T &a,T b){a = max (a,b);}
template <typename T> void chkmin (T &a,T b){a = min (a,b);}
vector <int> G[MAXN];
int n,len1,len2,f[MAXN],s[MAXN],t[MAXN];
void dfs (int u,int fa){
for (Int v : G[u]) if (v ^ fa) dfs (v,u),f[u] -= f[v];
int now = f[u] * (u > fa ? 1 : -1);
for (Int v : G[u]) if (v ^ fa) now += f[v] * (u > v ? 1 : -1);
if (now > 0) for (Int i = 1;i <= now;++ i) t[++ len1] = u;
else for (Int i = 1;i <= -now;++ i) s[++ len2] = u;
}
signed main(){
read (n);
for (Int i = 1;i <= n;++ i) read (f[i]);
for (Int i = 2,u,v;i <= n;++ i) read (u,v),G[u].push_back (v),G[v].push_back (u);
dfs (1,0),sort (s + 1,s + len2 + 1),sort (t + 1,t + len1 + 1);
write (len1),putchar ('\n');
for (Int i = 1;i <= len1;++ i) write (s[i]),putchar (' '),write (t[i]),putchar ('\n');
return 0;
}