W
e
l
c
o
m
e
: )

P8575 「DTOI-2」星之河 题解

P8575 「DTOI-2」星之河 题解

题目描述

P8575 「DTOI-2」星之河

题目解法

看题目就能感觉到是一道求偏序的题。所以我们先找偏序关系。

\(Red_i\)\(Blue_i\) 的关系题面已经给出,现在考虑子树关系。

自然而然地联想到 dfs 序。

先求出每个点的 dfs 序 \(dfn_i\),以及其子树的大小 \(size_i\)

如果点 \(j\) 在点 \(i\) 的子树中,那么就有 \(dfn_i<dfn_j<dfn_i+size_i\)

综上,可以得出 \(j\)\(i\) 有贡献的条件:

\[Red_j\leq Red_i\wedge Blue_j\leq Blue_i \wedge dfn_i<dfn_j<dfn_i+size_i \]

乍一看,好像是个四维偏序 (cdq 套 cdq)

但是由于最后一组条件比较特殊,可以化为三维偏序。

使用 cdq 分治。如果不会建议先做:【模板】三维偏序

在三维偏序模板中,用树状数组统计答案的时候统计的是 \([1,x_i)\) 该区间。

在本题中,用树状数组统计答案的时候我们统计 \((dfn_i,dfn_i+size_i)\) 区间。

除此之外就是裸的 cdq 分治。

同时需要注意一下排序部分 \(Blue_i,Red_i\) 升序,而 \(dfn_i\) 降序。

Code

#include<bits/stdc++.h>
using namespace std;
#define maxn 200005

vector<int> e[maxn];

int dfn[maxn], siz[maxn];
void dfs(int u, int f)
{
    dfn[u]=++*dfn;
    for(auto v:e[u])
        if(v!=f) 
            dfs(v, u), siz[u]+=siz[v]+1;
}

struct st
{
    int x, y, l, r, id;
    st(int X, int Y, int L, int R, int I): id(I), x(X), y(Y), l(L), r(R){}
};

bool cmp1(st a, st b)
{
    if(a.x!=b.x) return a.x<b.x;
    if(a.y!=b.y) return a.y<b.y;
    return a.l>b.l;
}

bool cmp2(st a, st b)
{
    if(a.y!=b.y) return a.y<b.y;
    if(a.l!=b.l) return a.l>b.l;
    return a.x<b.x;
}

vector<st> vc;

template<typename Tp>
struct BIT:vector<Tp>
{
    void modify(size_t i, Tp v) {for(;i<this->size();i+=i&-i) (*this)[i]+=v;}
    Tp query(size_t i)     {Tp r=0; for(;i;i-=i&-i) r+=(*this)[i]; return r;}
};

BIT<int> ta;

int ans[maxn];

void cdq(int l, int r)
{
    if(l==r) return;
    int mid=(l+r)>>1;
    cdq(l, mid); cdq(mid+1, r);
    sort(vc.begin()+l, vc.begin()+r+1, cmp2);
    for(int i=l;i<=r;i++)
        if(vc[i].x<=mid) ta.modify(vc[i].l, 1);
        else ans[vc[i].id]+=ta.query(vc[i].r)-ta.query(vc[i].l-1);
    for(int i=l;i<=r;i++)
        if(vc[i].x<=mid) 
            ta.modify(vc[i].l, -1);
}

signed main()
{
    int n;
    cin>>n;
    ta.resize(n+5);
    for(int i=1, u, v;i<n;i++)
    {
        cin>>u>>v;
        e[u].emplace_back(v);
        e[v].emplace_back(u);
    }
    dfs(1, 0);
    for(int i=1, r, b;i<=n;i++) 
    {
        cin>>r>>b;
        vc.emplace_back(r, b, dfn[i], min(dfn[i]+siz[i], n), i);
    }
    sort(vc.begin(), vc.end(), cmp1);
    for(int i=0;i<vc.size();i++) vc[i].x=i;
    cdq(0, n-1);
    for(int i=1;i<=n;i++) if(ans[i]) cout<<ans[i]<<'\n';
}
posted @ 2024-08-25 20:56  Jimmy-LEEE  阅读(22)  评论(0)    收藏  举报