【题解】P8575 「DTOI-2」星之河
【P8575】题解
一:【题面】
略
二:【解法】
每个节点打上dfn序列
每个节点有属性{a,b,c}表{红星亮度,蓝星亮度,dfn序}和siz
之后问题等价于
对于每个节点i求出多少节点j同时满足
- a[j]<=a[i]
- b[j]<=b[i]
- c[i]<c[j]<=c[i]+siz[i]-1
做CDQ分治求三维偏序,树状数组求区间和即可
三:【代码】
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
vector<int> mp[N];
int cnt=0;
int dfn[N],siz[N];
void dfs(int u,int fa){
dfn[u]=++cnt;
siz[u]=1;
for(auto v:mp[u]){
if(v==fa) continue;
dfs(v,u);
siz[u]+=siz[v];
}
}
struct node{
int id,a,b,c;
int ans;
}q[N<<1];
bool cmpa(node x,node y){
if(x.a!=y.a) return x.a<y.a;
if(x.b!=y.b) return x.b<y.b;
return x.c>y.c;
}
bool cmpb(node x,node y){
if(x.b!=y.b) return x.b<y.b;
return x.c>y.c;
}
int tree[N];
void update(int x,int d){
while(x<N){
tree[x]+=d;
x+=x&-x;
}
}
int query(int x){
int res=0;
while(x){
res+=tree[x];
x-=x&-x;
}
return res;
}
void CDQ(int l,int r){
if(l==r) return ;
int mid=l+r>>1;
CDQ(l,mid);CDQ(mid+1,r);
sort(q+l,q+mid+1,cmpb);sort(q+mid+1,q+r+1,cmpb);
int i=l,j=mid+1;
while(j<=r){
while(i<=mid&&q[i].b<=q[j].b){
update(q[i].c,1);
i++;
}
q[j].ans+=query(q[j].c+siz[q[j].id]-1)-query(q[j].c);
j++;
}
for(int k=l;k<i;k++){
update(q[k].c,-1);
}
}
int ans[N];
int main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
int n;cin>>n;
for(int i=1;i<n;i++){
int a,b;cin>>a>>b;
mp[a].push_back(b);
mp[b].push_back(a);
}
dfs(1,1);
int idx=0;
for(int i=1;i<=n;i++){
int b,c;cin>>b>>c;
q[++idx]={i,b,c,dfn[i],0};
}
sort(q+1,q+1+idx,cmpa);
CDQ(1,idx);
for(int i=1;i<=idx;i++) ans[q[i].id]+=q[i].ans;
for(int i=1;i<=n;i++){
if(ans[i]) cout<<ans[i]<<"\n";
}
return 0;
}
//c只会对<c的造成影响,所以要逆序排

浙公网安备 33010602011771号