题意
给定一棵 \(n\) 个节点的树,每个点有一个权值。有 \(m\) 个询问,每次给你 \(u,v,k\),你需要回答 \(u \text{ xor last}\) 和 \(v\) 这两个节点间第 \(k\) 小的点权。
其中 \(\text{last}\) 是上一个询问的答案,定义其初始为 \(0\),即第一个询问的 \(u\) 是明文。
对于 \(100\%\) 的数据,\(1\le n,m \le 10^5\)。
题解
树上主席树板子。全程独立码完,感觉主席树的代码应该是没问题了,只是还缺乏一些应用的练习。
众所周知查询第 k 小的主席树本质上是个前缀和。
众所周知这个世界上有个叫树上前缀和的东西。
众所周知常规的树上前缀和的式子是 \(dis_{u,v}=sum_u+sum_v-sum_{lca_{u,v}}-sum_{fa_{lca}}\) 。
然后就做完了。是不是特别容易呢?
const ll maxn=1e5+5;
struct node{
ll val,ls,rs;
};
ll n;
namespace hjt{
#define mid ((l+r)>>1)
node t[maxn*20];
ll cnt=0;
ll get(){
cnt++;
t[cnt].val=0;
t[cnt].ls=t[cnt].rs=-1;
return cnt;
}
void upd(ll x){
t[x].val=0;
if(t[x].ls>=0)t[x].val+=t[t[x].ls].val;
if(t[x].rs>=0)t[x].val+=t[t[x].rs].val;
}
void build(ll x,ll l,ll r){
if(l==r){
return ;
}
t[x].ls=get();
t[x].rs=get();
build(t[x].ls,l,mid);
build(t[x].rs,mid+1,r);
}
void init(){
for(ll i=0;i<=n;i++)get();
//cerr<<cnt<<endl;
build(0,1,n);
//cerr<<cnt<<endl;
}
void insert(ll u,ll v,ll l,ll r,ll k){
if(l==r){
t[v].val++;
return ;
}
if(k<=mid){
t[v].rs=t[u].rs;
t[v].ls=get();
insert(t[u].ls,t[v].ls,l,mid,k);
}
else {
t[v].ls=t[u].ls;
t[v].rs=get();
insert(t[u].rs,t[v].rs,mid+1,r,k);
}
upd(v);
// cerr<<u<<" "<<v<<" "<<t[v].val<<endl;
}
ll query(ll u,ll v,ll lc,ll fa,ll l,ll r,ll k){
if(l==r){
return l;
}
if(k<=t[t[u].ls].val+t[t[v].ls].val-t[t[lc].ls].val-t[t[fa].ls].val){
return query(t[u].ls,t[v].ls,t[lc].ls,t[fa].ls,l,mid,k);
}
return query(t[u].rs,t[v].rs,t[lc].rs,t[fa].rs,mid+1,r,k-(t[t[u].ls].val+t[t[v].ls].val-t[t[lc].ls].val-t[t[fa].ls].val));
}
#undef mid
}
ll a[maxn],b[maxn],tot;
vector<ll>e[maxn];
namespace lca{
ll fa[maxn][20],dep[maxn];
void dfs(ll x){
dep[x]=dep[fa[x][0]]+1;
hjt::insert(fa[x][0],x,1,n,a[x]);
// cerr<<fa[x][0]<<" "<<x<<" "<<a[x]<<endl;
//cerr<<x<<" "<<hjt::t[x].val<<" "<<hjt::t[fa[x][0]].val<<endl;
for(ll i=1;i<=17;i++){
fa[x][i]=fa[fa[x][i-1]][i-1];
if(!fa[x][i])break;
}
for(auto v:e[x]){
if(v==fa[x][0])continue;
fa[v][0]=x;
dfs(v);
}
}
ll query(ll u,ll v){
if(dep[u]<dep[v])swap(u,v);
for(ll i=17;i>=0;i--){
if(dep[fa[u][i]]>=dep[v])u=fa[u][i];
}
if(u==v)return u;
for(ll i=17;i>=0;i--){
if(fa[u][i]!=fa[v][i])u=fa[u][i],v=fa[v][i];
}
return fa[u][0];
}
}
ll m,lst;
void solve(){
n=R,m=R;
for(ll i=1;i<=n;i++){
a[i]=b[i]=R;
}
sort(b+1,b+1+n);
tot=unique(b+1,b+1+n)-b-1;
for(ll i=1;i<=n;i++){
a[i]=lower_bound(b+1,b+1+tot,a[i])-b;
//cerr<<a[i]<<endl;
}
hjt::init();
for(ll i=1;i<n;i++){
ll u=R,v=R;
e[u].push_back(v);
e[v].push_back(u);
}
lca::dfs(1);
for(ll i=0;i<=n;i++){
// cerr<<i<<" "<<lca::fa[i][0]<<" "<<hjt::t[i].val<<endl;
//cerr<<lca::fa[i][0]<<endl;
}
while(m--){
ll u=R,v=R,k=R;
u^=lst;
//cerr<<u<<" "<<v<<endl;
ll lc=lca::query(u,v);
//cerr<<<<endl;
lst=b[hjt::query(u,v,lc,lca::fa[lc][0],1,n,k)];
we(lst);
}
return ;
}
标签:Count,cnt,val,rs,tree,ll,LuoguP2633,fa,ls
From: https://www.cnblogs.com/rnfmabj/p/luogup2633.html