序
这一场是我们学校出的,结果出的非常残暴,第二题就比较复杂。第一题是个签到,我去写了,让队友去看了第二题。第一题签了半个多小时终于一次a了,然后去问队友第二题。听懂题意以后,我说了句:诶,我感觉这个题是不是可以用可持久化。队友:???
如果熟悉可持久化数据结构,这题其实就是一个sb题,不过我们三个都没怎么接触过可持久化,所以一次AC还是挺激动的。
题意
给你一棵树,每个点都有一个点权,而且父亲的点权大于他任意儿子的点权。让你从一个点开始走,要求只能走到点权在 l,r 范围内的点,问你能走到一共多少个点。有 1e5 次询问。
做法
首先可以利用倍增找到这个点可以走到的最高的祖先,这个问题就变成了在这个祖先的子树种查询有多少个点的值大于 l
这样先用dfs序把子树问题变成子段问题,然后离散化后向主席树按照dfs序的顺序插入每个点的值,然后差分容斥,用 第 r 次插入减去第 l-1 次插入的结果,得出答案。
其实可以用树状数组离线做,但是当时第一反应就是主席树,所以直接上去写了。
上代码:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <map>
#define int long long
#define MAXN 5000005
using namespace std;
typedef long long ll;
const ll maxn=300010;
struct node
{
int ls,rs,v;
}st[MAXN];int ptr;
void iniSt(int &p,int l,int r)
{
p=++ptr;
if(l==r) return;
int mid=(l+r)/2;
iniSt(st[p].ls,l,mid);
iniSt(st[p].rs,mid+1,r);
}
int modify(int p,int l,int r,int x,int v)
{
int np=++ptr;
st[np]=st[p];
if(l==r)
{
st[np].v+=v;
return np;
}
int mid=(l+r)/2;
if(x<=mid)
st[np].ls=modify(st[np].ls,l,mid,x,v);
else
st[np].rs=modify(st[np].rs,mid+1,r,x,v);
st[np].v=st[st[np].ls].v+st[st[np].rs].v;//用两个儿子更新爸爸
return np;
}
int rt[MAXN];
int query(int p,int l,int r,int al,int ar)
{
if(al<=l&&ar>=r)
return st[p].v;
if(ar<l||al>r)return 0;
int mid=(l+r)/2;
return query(st[p].ls,l,mid,al,ar)+query(st[p].rs,mid+1,r,al,ar);
}
struct Node
{
ll v;
ll next;
}e[2*maxn];
ll n,p[maxn],t=0;
ll tpr[maxn],New[maxn],ano[maxn];
ll ask[maxn][4];
map<ll,ll> mp;
void insert(ll u,ll v)
{
e[t].v=v;
e[t].next=p[u];
p[u]=t++;
}
ll dfn[maxn],parent[maxn][30],son[maxn],times=0;
void dfs(ll u,ll pre)
{
dfn[u]=++times;
ano[times]=tpr[u];
son[u]=1;
for(ll i=p[u];i!=-1;i=e[i].next)
{
ll v=e[i].v;
if(v!=pre)
{
dfs(v,u);
son[u]+=son[v];
parent[v][0]=u;
}
}
}
ll getroot(ll x,ll l,ll r)
{
while(1)
{
ll now=0;
while(tpr[parent[x][now]]<=r && parent[x][now]!=0)
now++;
now--;
if(now==-1)
return x;
x=parent[x][now];
}
}
signed main()
{
memset(p,-1,sizeof(p));
scanf("%lld",&n);
for(ll i=1;i<=n-1;i++)
{
ll u,v;
scanf("%lld%lld",&u,&v);
insert(u,v);
insert(v,u);
}
for(ll i=1;i<=n;i++)
{
scanf("%lld",&tpr[i]);
New[i]=tpr[i];
}
ll cnt=n,q;
scanf("%lld",&q);
for(ll i=1;i<=q;i++)
{
scanf("%lld%lld%lld",&ask[i][0],&ask[i][1],&ask[i][2]);
New[++cnt]=ask[i][1];
New[++cnt]=ask[i][2];
}
sort(New+1,New+1+cnt);
ll m=unique(New+1,New+1+cnt)-New-1;
for(ll i=1;i<=m;i++)
mp[New[i]]=i;
for(ll i=1;i<=n;i++)
tpr[i]=mp[tpr[i]];
dfs(1,-1);
iniSt(rt[0],1,m);
for(int i=1;i<=times;i++)
{
rt[i]=modify(rt[i-1],1,m,ano[i],1);
}
for(ll level=1;level<=20;level++)
for(ll i=1;i<=n;i++)
parent[i][level]=parent[parent[i][level-1]][level-1];
for(ll i=1;i<=q;i++)
{
ll x=ask[i][0],l=ask[i][1],r=ask[i][2];
if(tpr[x]<mp[l] || tpr[x]>mp[r])
{
printf("0\n");
continue;
}
ll root=getroot(x,mp[l],mp[r]);
cout<<query(rt[dfn[root]+son[root]-1],1,m,mp[l],m)-query(rt[dfn[root]-1],1,m,mp[l],m)<<endl;
}
return 0;
}