区间链并
题目大意:
给你一棵 \(n\) 个点的树以及树上的 \(m\) 条链,另 \(S_i\) 表示其中第 \(i\) 条链的点集。\(q\) 次询问每次给出一个区间 \([l,r]\),请你输出 \(|S_l\cup S_{l+1}\cup\dots\cup S_{r-1}\cup S_r|\)。
\(1\le n,m,q\le10^5\)。
考虑扫描线。
我们将询问区间按右端点从小到大排序,然后扫描 \(m\) 条链。对于点 \(i\),我们只需要记录到现在为止覆盖它的编号最大的链。
于是我们考虑怎么记录这个东西。扫到第 \(i\) 条链时,我们要做的操作是将树上的一条链上的所有点的颜色全都推平成 \(i\),而这个可以用树剖+odt 轻松解决,具体思路就是类似于树剖求 lca,不停地向上跳重链,然后用 odt 顺便推平走过的路径。这样复杂度是 \(O(m\log^2n)\) 的。
考虑怎么查询。我们需要在扫链的时候同时扫询问区间。当我们将第 \(i\) 条链对应的操作做完之后,就需要去计算右端点恰好等于 \(i\) 的询问区间的答案。显而易见,此时区间 \([l,i]\) 的答案就是所有颜色大于等于 \(l\) 的点。于是容易想到用权值树状数组维护每种颜色对应的点有几个,在 odt 推平的时候顺便维护一下就好了。时间复杂度 \(O(m\log^2n+q\log n)\)。
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
vector<int> v[N];
int son[N],siz[N],top[N],dep[N],fa[N],dfn[N],df;
int n,m,q;
void dfs1(int u,int f){
fa[u]=f;
siz[u]=1;
dep[u]=dep[f]+1;
for(auto i:v[u]){
if(i!=f){
dfs1(i,u);
if(siz[i]>siz[son[u]]) son[u]=i;
siz[u]+=siz[i];
}
}
}
void dfs2(int u,int tp){
top[u]=tp;
dfn[u]=++df;
if(son[u]) dfs2(son[u],tp);
for(auto i:v[u])
if(i!=fa[u]&&i!=son[u]) dfs2(i,i);
}
struct Node{
int l,r;
mutable long long v;
}Link[N];
struct query{
int id;
int l,r;
long long ans;
}Q[N];
long long tr[N];
set<Node> odt;
bool operator<(Node p1,Node p2){
return p1.l<p2.l;
}
int lowbit(int x){
return x&-x;
}
void add(int x,int k){
for(;x<=n;x+=lowbit(x)) tr[x]+=k;
}
long long ask(int x){
long long ans=0;
for(;x;x-=lowbit(x)) ans+=tr[x];
return ans;
}
auto split(int x){
auto xx=odt.lower_bound({x,0,0ll});
if(xx!=odt.end()&&xx->l==x) return xx;
xx--;
int l=xx->l,r=xx->r,v=xx->v;
odt.erase(xx);
odt.insert({l,x-1,v});
return odt.insert({x,r,v}).first;
}
void assign(int l,int r,long long v){
auto fqr=split(r+1),fql=split(l);
for(auto i=fql;i!=fqr;i++){
if(i->v) add(i->v,i->l-i->r-1);
add(v,i->r-i->l+1);
}
odt.erase(fql,fqr);
odt.insert({l,r,v});
}
void Change(int u,int v,int val){
while(top[u]!=top[v]){
if(dep[fa[top[u]]]<dep[fa[top[v]]]) swap(u,v);
assign(dfn[top[u]],dfn[u],val);
u=fa[top[u]];
}
if(dep[u]>dep[v]) swap(u,v);
assign(dfn[u],dfn[v],val);
}
int cmp1(query q1,query q2){
if(q1.r==q2.r) return q1.l<q2.l;
return q1.r<q2.r;
}
int cmp2(query q1,query q2){
return q1.id<q2.id;
}
int main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
cin>>n>>m>>q;
for(int i=1;i<n;i++){
int x,y;
cin>>x>>y;
v[x].emplace_back(y),v[y].emplace_back(x);
}
dfs1(1,0);
dfs2(1,1);
odt.insert({1,n,0});
for(int i=1;i<=m;i++){
int x,y;
cin>>x>>y;
Link[i]={x,y,0};
}
for(int i=1;i<=q;i++){
int x,y;
cin>>x>>y;
Q[i]={i,x,y,0};
}
sort(Q+1,Q+q+1,cmp1);
int j=1;
for(int i=1;i<=m;i++){
Change(Link[i].l,Link[i].r,i);
while(j<=q&&Q[j].r==i) Q[j].ans=ask(Q[j].r)-ask(Q[j].l-1),j++;
}
sort(Q+1,Q+q+1,cmp2);
for(int i=1;i<=q;i++) cout<<Q[i].ans<<'\n';
}
i AM a LAD,ANd Fine.

浙公网安备 33010602011771号