[Ynoi2011] 成都七中 题解
题面
看到处理连通块问题想到点分治,条件可以转化为若 \(u\) 和 \(x\) 在同一个连通块中,则 \(u\) 到 \(x\) 的路径上所有点都在 \([l,r]\) 内。我们可以每层分治都处理出 \(x\) 到分治中心的路径,再回答询问。每一个点一定会被一个分治中心访问到,且它被访问的第一次就是最优的情况。
递归得到当前 \(l,r\) 表示中心到 \(x\) 的路径上编号最小的点是 \(l\),最大的点是 \(r\),存进 vector 里面。我们再把当前能处理的询问都存进另一个 vector 里面,然后做一个双指针,把询问和路径都按 \(r\) 排序,因为要求路径的 \(l>=L_q\) 且 \(r<=R_q\),所以我们对每一种颜色都在 bit 对应的 \(l\) 上面加上 \(1\),如果这个颜色已经出现过,我们在最大的 \(l\) 上加这个 \(1\),因为这样最优。询问树状数组的 \([l-1,r]\) 区间就可以得到颜色数量了。
说实话感觉没那么难,但是就是有点难以想到把路径约束转化为 \(\min,\max\) 的限制。
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define _int __int128
#define ull unsigned long long
#define pii pair<int,int>
#define fst first
#define scd second
#define pq priority_queue
#define mkp make_pair
#define popcount(x) __builtin_popcount(x)
#define endl '\n'
int n,m;
const int N = 1e5+10;
vector<int>g[N];
int c[N],maxp[N],siz[N],rt,tot,vis[N],ans[N],lst[N],st[N],top;
struct qy{
int l,r,id;
};
vector<qy>q[N],p,w;
int lowbit(int x){
return x&(-x);
}
int t[N];
void add(int p,int v){
for(int i=p;i<=n;i+=lowbit(i)){
t[i]+=v;
}
}
int ask(int p){
int res=0;
for(int i=p;i;i-=lowbit(i)){
res+=t[i];
}
return res;
}
int query(int l,int r){
return ask(r)-ask(l-1);
}
void getct(int u,int f){
siz[u]=1;
maxp[u]=0;
for(auto v:g[u]){
if(v==f||vis[v])continue;
getct(v,u);
siz[u]+=siz[v];
maxp[u]=max(maxp[u],siz[v]);
}
maxp[u]=max(maxp[u],tot-siz[u]);
if(maxp[u]<maxp[rt])rt=u;
}
bool cmp(qy a,qy b){
return a.r<b.r;
}
void dfs(int x,int f,int l,int r){
siz[x]=1;
p.push_back({l,r,c[x]});
for(auto [L,R,id]:q[x]){
if(ans[id]||l<L||r>R)continue;
w.push_back({L,R,id});
}
for(auto v:g[x]){
if(vis[v]||v==f)continue;
dfs(v,x,min(v,l),max(v,r));
siz[x]+=siz[v];
}
}
void solve(int x){
p.clear();w.clear();
dfs(x,0,x,x);
sort(p.begin(),p.end(),cmp);
sort(w.begin(),w.end(),cmp);
int cur=0;
for(auto [l,r,id]:w){
while(cur<p.size()&&p[cur].r<=r){
int c=p[cur].id;
if(!lst[c]){
lst[c]=p[cur].l;
add(p[cur].l,1);
st[++top]=p[cur].id;
}else if(p[cur].l>lst[c]){
add(lst[c],-1);
lst[c]=p[cur].l;
add(lst[c],1);
}
cur++;
}
ans[id]=query(l,n);
}
while(top){
add(lst[st[top]],-1);
lst[st[top]]=0;
top--;
}
}
void ctd(int x){
vis[x]=1;
solve(x);
for(auto v:g[x]){
if(vis[v])continue;
tot=siz[v];
maxp[rt=0]=N;
getct(v,0);
ctd(rt);
}
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>c[i];
}
for(int i=1;i<n;i++){
int u,v;
cin>>u>>v;
g[u].push_back(v);
g[v].push_back(u);
}
for(int i=1;i<=m;i++){
int l,r,x;
cin>>l>>r>>x;
q[x].push_back({l,r,i});
}
tot=n;
maxp[rt]=N;
getct(1,0);
ctd(rt);
for(int i=1;i<=m;i++){
cout<<ans[i]<<endl;
}
return 0;
}

浙公网安备 33010602011771号