题面
n
,
m
,
q
≤
1
0
5
n,m,q \le 10^5
n,m,q≤105
分析
很容易想出 n log 2 n n\log^2 n nlog2n的做法,用点减边的方法求连通块数,比如:
- 树剖后维护颜色块,从右往左枚举左端点后维护右端点答案。
- 用LCT的access操作代替上述做法的树剖。注意此处不能make_root,因此事实上操作数量还要翻倍…
由于树剖的log很难卡满,因此上述两做法还是可以通过此题的(甚至比一个log还快,小粉兔真牛批,其实是我打搓了)
林立给出了一个log的做法:
注意到两条路径相交,深度大的LCA必然被覆盖。
同理,整个连通块只有最高的LCA不会被其他路径覆盖(LCA重合除外)。
因此,只要计算出某个机器人的LCA在哪个区间内没有覆盖,就可以解决此题了。
求左边第一个覆盖此点的机器人,只需要LCT的链赋值即可。
因此左右扫两遍,再加一个统计答案的操作就可以
O
(
n
log
n
)
O(n \log n)
O(nlogn)了。
注意LCA重合的情况,这时候我们只需要默认编号小的覆盖编号大的即可。
总结
将连通块个数转化为没有被覆盖的LCA个数,是本题的关键。
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
int n,m,q;
void read(int &x) {
char c; while((c=getchar()) > '9' || c < '0');
x = c - '0'; while((c=getchar()) >= '0' && c <= '9') x = x * 10 + c - '0';
}
namespace tree{
int final[N], nex[N * 2], to[N * 2], tot;
void link(int x,int y) {
to[++tot] = y, nex[tot] = final[x], final[x] = tot;
}
int g[N][17], dep[N], dfn[N], stm, R[N];
void dfs(int x) {
dfn[x] = ++ stm;
dep[x] = dep[g[x][0]] + 1;
for(int i = 1; i < 17; i++) g[x][i] = g[g[x][i - 1]][i - 1];
for(int i = final[x]; i; i = nex[i]) {
int y = to[i]; if (y != g[x][0]) {
g[y][0] = x;
dfs(y);
}
}
R[x] = stm;
}
int lca(int x,int y,int &u,int &v){
int fl = 0;
if (dep[x] < dep[y]) fl = 1, swap(x, y);
for(int i = 16; ~i; i--) if (dep[g[x][i]] >= dep[y])
x = g[x][i];
for(int i = 16; ~i; i--) if (g[x][i] != g[y][i]) {
x = g[x][i], y = g[y][i];
}
u = x, v = y;
if (fl) swap(u, v);
return g[x][0];
}
int jump(int fa, int x) {
for(int i = 16; ~i; i--) if (dep[g[x][i]] > dep[fa]) x = g[x][i];
return x;
}
}
pair<int,int> s[N], es[N][2];
int ac[N];
vector<pair<int,int> > qry[N];
int ans[N];
namespace BIT{
#define lowbit(x) ((x) & -(x))
int bit[N];
inline int query(int x) {
x++;
int ret = 0; for(; x; x -= lowbit(x)) {
ret += bit[x];
}
return ret;
}
inline void change(int x,int v) {
x++;
for(; x <= n + 1; x += lowbit(x)) bit[x] += v;
}
}
namespace LCT{
int se[N], fa[N], c[N][2], tag[N], v[N];
#define c0 c[x][0]
#define c1 c[x][1]
void rev(int x) {
if(!x)return;
tag[x] ^= 1;
swap(c0, c1);
}
void setvalue(int x, int vv) {
if(!x)return;
v[x] = se[x] = vv;
}
void down(int x) {
if (tag[x]) {
rev(c0), rev(c1);
tag[x] = 0;
}
if (se[x]) {
setvalue(c0, se[x]);
setvalue(c1, se[x]);
se[x] = 0;
}
}
#define lr(x) ((c[fa[x]][1]) == (x))
#define isroot(x) (c[fa[x]][0] != (x) && c[fa[x]][1] != (x))
void rotate(int x) {
int y = fa[x], z = lr(x);
c[y][z] = c[x][1 - z];
if (c[x][1 - z]) fa[c[x][1 - z]] = y;
if (!isroot(y)) c[fa[y]][lr(y)] = x;
fa[x] = fa[y];
c[x][1 - z] = y;
fa[y] = x;
}
void splay(int x) {
static int Q[N]; int z=0;
for(z=x;!isroot(z);z=fa[z]) {
Q[++Q[0]] = z;
}down(z);
while(Q[0])down(Q[Q[0]--]);
while(!isroot(x)) {
if(!isroot(fa[x])){
if(lr(x)==lr(fa[x])) rotate(fa[x]); else rotate(x);
}
rotate(x);
}
}
void access(int x) {
for(int i = 0; x; i = x, x = fa[x]) {
splay(x);
c[x][1] = i;
}
}
void make_root(int x) {
access(x), splay(x);
rev(x);
}
}
int L[N], sR[N];
void solve() {
using namespace LCT;
for(int i = 1; i <= n; i++) fa[i] = tree::g[i][0];
for(int i = 1; i <= m; i++) {
splay(ac[i]);
L[i] = v[ac[i]];
int a = s[i].first, b = s[i].second;
make_root(a), access(b), splay(b);
setvalue(b, i);
}
for(int i = 1; i <= n; i++) se[i] = 0, v[i] = m + 1;
for(int i = m; i; i--) {
splay(ac[i]);
sR[i] = v[ac[i]];
for(int j = 0; j < 2; j++) {
int a = es[i][j].first, b = es[i][j].second;
if (!a) continue;
make_root(a), access(b), splay(b);
setvalue(b, i);
}
}
}
vector<int> del[N];
int main() {
freopen("tree.in","r",stdin);
// freopen("tree.out","w",stdout);
cin>>n>>m>>q;
for(int i = 1; i < n; i++) {
int u,v; read(u), read(v);
tree::link(u,v);
tree::link(v,u);
}
tree::dfs(1);
for(int i = 1; i <= m; i++) {
int a = 0, b = 0;
read(a),read(b);
using namespace tree;
if (dfn[a] > dfn[b]) swap(a, b);
s[i] = make_pair(a, b);
if (dfn[b] <= R[a]) {
ac[i] = a;
if (a == b) continue;
int g = tree::jump(a, b);
es[i][0] = make_pair(g, b);
} else {
int u = 0, v = 0;
int g = ac[i] = tree::lca(a,b,u,v);
es[i][0] = make_pair(u, a);
es[i][1] = make_pair(v, b);
}
}
for(int i = 1; i <= q; i++) {
int l,r; read(l), read(r);
qry[l].push_back(make_pair(r, i));
}
solve();
using namespace BIT;
for(int i = n; i; i--) {
change(i, 1);
change(sR[i], -1);
del[L[i]].push_back(i);
for(int z : del[i]) {
change(z, -1);
change(sR[z], 1);
}
for(pair<int,int> z : qry[i]) {
ans[z.second] = query(z.first);
}
}
for(int i = 1; i <= q; i++) printf("%d\n", ans[i]);
}