luogu P2633 Count on a tree

思路

强制在线--主席树
以1为root建主席树 (就是在树上建树,差不多)
rt[i]就是1到i的路径上的一棵树的root
其实我感觉,主席树之间的运算差不多于加减
类似lca的运算
root(1到x)+root(1到y)-root(lca)-root(fa[lca])
查询他们的第k小就OK

错误 or debug的地方

错误:运算写错了,算是思路不清晰吧 、、、
debug:和他xor的是原来的数,不是lsh之后的数字、、、

代码

#include <bits/stdc++.h>
#define FOR(i,a,b) for(int i=a;i<=b;++i)
using namespace std;
const int maxn=1e5+7;
int read() {
    int x=0,f=1;char s=getchar();
    for(;s>'9'||s<'0';s=getchar()) if(s=='-') f=-1;
    for(;s>='0'&&s<='9';s=getchar()) x=x*10+s-'0';
    return x*f;
}
int n,m,a[maxn],b[maxn];
struct node {
    int v,nxt;
}e[maxn<<1];
int head[maxn<<1],tot;
void add_edge(int u,int v) {
    e[++tot].v=v;
    e[tot].nxt=head[u];
    head[u]=tot;
}
namespace LCA {
    int dep[maxn],st[maxn][21];
    void dfs(int u,int f) {
        for(int i=head[u];i;i=e[i].nxt) {
            int v=e[i].v;
            if(v==f) continue;
            st[v][0]=u;
            dep[v]=dep[u]+1;
            dfs(v,u);
        }
    }
    int Lca(int x,int y) {
        if(dep[x]<dep[y]) swap(x,y);
        for(int i=20;i>=0;--i)
            if(dep[st[x][i]]>=dep[y]) x=st[x][i];
        if(x==y) return x;
        for(int i=20;i>=0;--i)
            if(st[x][i]!=st[y][i]) x=st[x][i],y=st[y][i];
        return st[x][0];
    }
    void init() {
        dep[1]=1;
        dfs(1,0);
        FOR(j,1,20) FOR(i,1,n)
            st[i][j]=st[st[i][j-1]][j-1]; 
    }
}
using namespace LCA;
struct edge {
    int ch[2],siz;
}t[maxn*30];
int rt[maxn],cnt;
void build(int &now,int old,int l,int r,int k) {
    now=++cnt;
    t[now]=t[old];
    t[now].siz++;
    if(l==r) return;
    int mid=(l+r)>>1;
    if(k<=mid) build(t[now].ch[0],t[old].ch[0],l,mid,k);
    else build(t[now].ch[1],t[old].ch[1],mid+1,r,k);
}
void DFS(int u,int f) {
    build(rt[u],rt[f],1,n,a[u]);
    for(int i=head[u];i;i=e[i].nxt) {
        int v=e[i].v;
        if(v==f) continue;
        DFS(v,u);
    }
}
int query(int a,int b,int c,int d,int l,int r,int k) {
    if(l==r) return l;
    int tot=t[t[a].ch[0]].siz+t[t[b].ch[0]].siz-t[t[c].ch[0]].siz-t[t[d].ch[0]].siz;
    int mid=(l+r)>>1;
    if(tot>=k) return query(t[a].ch[0],t[b].ch[0],t[c].ch[0],t[d].ch[0],l,mid,k);
    else return query(t[a].ch[1],t[b].ch[1],t[c].ch[1],t[d].ch[1],mid+1,r,k-tot);
}
int main() {
    //@read
    n=read(),m=read();
    FOR(i,1,n) a[i]=b[i]=read();
    FOR(i,2,n) {
        int x=read(),y=read();
        add_edge(x,y);
        add_edge(y,x);
    }
    //@lsh
    sort(b+1,b+1+n);
    int len=unique(b+1,b+1+n)-b-1;
    FOR(i,1,n) a[i]=lower_bound(b+1,b+1+len,a[i])-b;
    //@lca_init
    init();
    //@build
    DFS(1,0);
    //@work
    int lastans=0;
    FOR(i,1,m) {
        int u=read(),v=read(),k=read();
        u=(u^lastans);
        int lca=Lca(u,v);
        lastans=b[query(rt[u],rt[v],rt[lca],rt[st[lca][0]],1,n,k)];
        cout<<lastans<<"\n"; 
    }
    return 0;
}
全部评论

相关推荐

vegetable_more_exercise:1-1.5万,没错啊,最少是1人民币,在区间内
点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务