【BZOJ】2588: Spoj 10628. Count on a tree

传送门 http://www.lydsy.com/JudgeOnline/problem.php?id=2588

Solution

读入玩得太骚玩挂了QwQ

每个点维护它到根的这条链上的所有权值
使用值域线段树,可以用类似于可持久化的方法

这样查询就可以用u,v,lca(u,v),father[lac(u,v)]四个点对应的值域线段树相减得到解

#include<stdio.h>
#include<algorithm>
#define cint const int &
#define l(k) t[k].lson
#define r(k) t[k].rson
#define N 100005
using namespace std;
typedef long long ll;
  
int tot,s[N],c[N],dep[N],f[N][17],n,m,rt[N],aim;
ll a[N],d[N],ans;
  
struct edge{int v,n;}e[N<<1];
inline void push(cint u,cint v){e[++tot]=(edge){v,s[u]};s[u]=tot;}
struct node{int sum,lson,rson;}t[N*20];
inline bool cmp(cint x,cint y){return a[x]<a[y];}
  
void ins(int &k,cint lk,cint l,cint r)
{
    if (!k) k=++tot;
    if (l==r){t[k].sum++;return;}
    int mid=l+r>>1;
    if (aim<=mid){ins(l(k),l(lk),l,mid);r(k)=r(lk);}
    else{ins(r(k),r(lk),mid+1,r);l(k)=l(lk);}
    t[k].sum=t[l(k)].sum+t[r(k)].sum;
}
  
void find(cint k1,cint k2,cint k3,cint k4,cint l,cint r,cint aim)
{
    if (l==r){ans=d[l];return;}
    int mid=l+r>>1,lsum=t[l(k1)].sum+t[l(k2)].sum-t[l(k3)].sum-t[l(k4)].sum;
    if (aim<=lsum) find(l(k1),l(k2),l(k3),l(k4),l,mid,aim);
    else find(r(k1),r(k2),r(k3),r(k4),mid+1,r,aim-lsum); 
}
  
void dfs(cint k,cint fa)
{
    dep[k]=dep[f[k][0]=fa]+1;
    for (int i=1;(1<<i)<dep[k];i++) f[k][i]=f[f[k][i-1]][i-1];
    aim=a[k];ins(rt[k],rt[fa],1,n);
    for (int i=s[k];i;i=e[i].n) if (e[i].v!=fa) dfs(e[i].v,k);
}
  
inline int lca(int u,int v)
{
    if (dep[u]<dep[v]) swap(u,v);
    for (int i=16;0<=i;i--) if ((1<<i)+dep[v]<=dep[u]) u=f[u][i];
    if (u==v) return u;
    for (int i=16;0<=i;i--) if (f[u][i]!=f[v][i]) u=f[u][i],v=f[v][i];
    return f[u][0];
}
  
int main()
{
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;i++) scanf("%lld",a+i);
    for (int i=1;i<=n;i++) c[i]=i;
    sort(c+1,c+n+1,cmp);
    for (int i=1;i<=n;i++) d[i]=a[c[i]],a[c[i]]=i;
    for (int i=1,u,v;i<n;i++) scanf("%d%d",&u,&v),push(u,v),push(v,u);
    dfs(1,0);
    for (int u,v,k,ac,i=1;i<=m;i++)
    {
        ll ui;
        scanf("%lld%d%d",&ui,&v,&k);u=ui^ans;
        ac=lca(u,v);
        find(rt[u],rt[v],rt[ac],rt[f[ac][0]],1,n,k);
        printf("%lld",ans);
        if (i<m) printf("\n");
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值