*题解:P7880 [Ynoi2006] rldcot
解析
考虑每个 lca 对应的点对,对于一个点 \(x\),\(\operatorname{lca}(u,v)=x\) 当且仅当 \(u\) 和 \(v\) 来自于 \(x\) 的不同子树或者 \(u,v\) 中至少有一个是 \(x\)。 然而这 \(O(n^2)\) 个点对并不是都有用,对于点对 \((u,v),(x,y)\) 满足 \(\operatorname{lca}(u,v)=\operatorname{lca}(x,y),u \le x \le y \le v\),点对 \((u,v)\) 是没有用的,因为如果询问覆盖了 \([u,v]\) 就必定覆盖了 \([x,y]\),只保留 \((x,y)\) 不影响结果。于是就有一种想法,在 \(x\) 的子树统计这样的极短区间 \([u,v]\) 使得 \(\operatorname{lca}(u,v) = x\),统计方式就是对于一个点 \(u\),找 \(u\) 在其他子树中的前驱和后继。这个过程可以使用启发式合并 + set 来实现,重儿子所在子树信息保留,对于其余子树,遍历的同时尝试在 set 里找前驱后继,结束后再把子树内的点加入 set。根据启发式合并的复杂度,可以得知处理出的区间数量是 \(O(n\log n)\) 的。
现在问题变为给定若干个带有颜色的区间,再给定询问区间,求它所包含的颜色区间中有多少种颜色。考虑扫描线,从右往左扫,维护 \(pos_i\) 表示当前在扫描线右边的区间中颜色为 \(i\) 的右端点位置最小值。查询 \([l,r]\) 就变为查询有多少个 \(i\) 满足 \(pos_i\le r\),可以使用树状数组进行前缀查询。
时间复杂度 \(O(n\log^2n)\)。
代码
#include <bits/stdc++.h>
#define ls(p) ((p) << 1)
#define rs(p) (((p) << 1) | 1)
#define mid ((l + r) >> 1)
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N = 1e5 + 5,M = 5e5,mod = 998244353;
vector<pii> t[N];
ll dep[N];
int siz[N],son[N],cnt[N],pos[N];
int b[N];
int res[M];
int read(){
int a = 1,x = 0;
char ch = getchar();
while(ch > '9' || ch < '0'){
if(ch == '-') a = -1;
ch = getchar();
}
while(ch >= '0' && ch <= '9'){
x = x * 10 + ch - '0';
ch = getchar();
}
return a * x;
}
void modi(int x,int k){
for(;x < N;x += x & -x){
b[x] += k;
}
}
int ask(int x){
int res = 0;
for(;x;x -= x & -x){
res += b[x];
}
return res;
}
struct Seg{
int l,r;
ll d;
friend bool operator < (Seg a,Seg b){
return a.l < b.l;
}
};
struct Query{
int l,r,id;
friend bool operator < (Query a,Query b){
return a.l < b.l;
}
};
vector<Seg> sg;
void dfs(int x,int f,ll d){
siz[x] = 1;
dep[x] = d;
for(pii p : t[x])if(p.first != f){
int nx = p.first,w = p.second;
dfs(nx,x,d + w);
siz[x] += siz[nx];
if(siz[nx] > siz[son[x]]) son[x] = nx;
}
}
set<int> s;
void calc(int x,int f,ll d){
auto it = s.lower_bound(x);
if(it != s.end()) sg.push_back({x,*it,d});
if(it != s.begin()) sg.push_back({*prev(it),x,d});
for(pii p : t[x])if(p.first != f){
int nx = p.first;
calc(nx,x,d);
}
}
void add(int x,int f){
for(pii p : t[x])if(p.first != f){
int nx = p.first;
add(nx,x);
}
s.insert(x);
}
void clear(){
s.clear();
}
void sol(int x,int f){
for(pii p : t[x])if(p.first != f && p.first != son[x]){
int nx = p.first;
sol(nx,x);
clear();
}
if(son[x]){
sol(son[x],x);
}
for(pii p : t[x])if(p.first != f && p.first != son[x]){
int nx = p.first;
calc(nx,x,dep[x]);
add(nx,x);
}
s.insert(x);
auto it = s.lower_bound(x);
if(it != s.end()) sg.push_back({x,*it,dep[x]});
if(it != s.begin()) sg.push_back({*prev(it),x,dep[x]});
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
memset(pos,127,sizeof(pos));
// freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
int n = read(),m = read();
for(int i=1;i<n;i++){
int u = read(),v = read(),d = read();
t[u].push_back({v,d});
t[v].push_back({u,d});
}
dfs(1,0,0);
sol(1,0);
vector<ll> v;
for(int i=1;i<=n;i++){
v.push_back(dep[i]);
}
sort(v.begin(),v.end());
v.erase(unique(v.begin(),v.end()),v.end());
for(int i=0;i<sg.size();i++){
sg[i].d = lower_bound(v.begin(),v.end(),sg[i].d) - v.begin() + 1;
}
sort(sg.begin(),sg.end());
vector<Query> q;
for(int i=1;i<=m;i++){
int l = read(),r = read();
q.push_back({l,r,i});
}
sort(q.begin(),q.end());
int p1 = q.size() - 1,p2 = sg.size() - 1;
for(int i=n;i>=1;i--){
while(p2 >= 0 && sg[p2].l == i){
if(sg[p2].r < pos[sg[p2].d]){
if(pos[sg[p2].d] < 2e9){
modi(pos[sg[p2].d],-1);
}
pos[sg[p2].d] = sg[p2].r;
modi(sg[p2].r,1);
}
p2--;
}
while(p1 >= 0 && q[p1].l == i){
res[q[p1].id] = ask(q[p1].r);
p1--;
}
}
for(int i=1;i<=m;i++){
cout<<res[i]<<'\n';
}
return 0;
}

浙公网安备 33010602011771号