bzoj 2588: Spoj 10628. Count on a tree LCA+主席树

2588: Spoj 10628. Count on a tree

Time Limit: 12 Sec  Memory Limit: 128 MB
[Submit][Status][Discuss]

Description

给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权。其中lastans是上一个询问的答案,初始为0,即第一个询问的u是明文。

Input

第一行两个整数N,M。

第二行有N个整数,其中第i个整数表示点i的权值。

后面N-1行每行两个整数(x,y),表示点x到点y有一条边。

最后M行每行两个整数(u,v,k),表示一组询问。

Output

M行,表示每个询问的答案。最后一个询问不输出换行符

Sample Input

8 5
105 2 9 3 8 5 7 7
1 2
1 3
1 4
3 5
3 6
3 7
4 8
2 5 1
0 5 2
10 5 3
11 5 4
110 8 2

Sample Output

2
8
9
105
7

HINT

HINT:

N,M<=100000

暴力自重。。。

Source

鸣谢seter

dfs序,然后求LCA;

分成两条链求第K小;

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<iostream>
#include<cstdio>
#include<cmath>
#include<string>
#include<queue>
#include<algorithm>
#include<stack>
#include<cstring>
#include<vector>
#include<list>
#include<set>
#include<map>
using namespace std;
#define ll long long
#define pi (4*atan(1.0))
#define eps 1e-14
#define bug(x)  cout<<"bug"<<x<<endl;
const int N=1e5+30010,M=1e6+10,inf=2147483647;
const ll INF=1e18+10,mod=2147493647;
struct Chairmantree
{
    int rt[N*20],ls[N*20],rs[N*20],sum[N*20];
    int tot;
    void init()
    {
        tot=0;
    }
    void build(int l,int r,int &pos)
    {
        pos=++tot;
        sum[pos]=0;
        if(l==r)return;
        int mid=(l+r)>>1;
        build(l,mid,ls[pos]);
        build(mid+1,r,rs[pos]);
    }
    void update(int p,int c,int pre,int l,int r,int &pos)
    {
        pos=++tot;
        ls[pos]=ls[pre];
        rs[pos]=rs[pre];
        sum[pos]=sum[pre]+c;
        if(l==r)return;
        int mid=(l+r)>>1;
        if(p<=mid)
            update(p,c,ls[pre],l,mid,ls[pos]);
        else
            update(p,c,rs[pre],mid+1,r,rs[pos]);
    }
    int rank(int s,int e,int L,int R,int l,int r)
    {
        if(L<=l&&r<=R)return sum[e]-sum[s];
        int mid=(l+r)>>1;
        int ans=0;
        if(L<=mid)
            ans+=rank(ls[s],ls[e],L,R,l,mid);
        if(R>mid)
            ans+=rank(rs[s],rs[e],L,R,mid+1,r);
        return ans;
    }
    int query(int L,int R,int S,int T,int l,int r,int k)
    {
        if(l==r)return l;
        int mid=(l+r)>>1;
        int x=sum[ls[R]]-sum[ls[L]]+sum[ls[T]]-sum[ls[S]];
        if(k<=x) return query(ls[L],ls[R],ls[S],ls[T],l,mid,k);
        else return query(rs[L],rs[R],rs[S],rs[T],mid+1,r,k-x);
    }
};
Chairmantree tree;
struct edge
{
    int v,next;
}edge[N<<1];
int head[N],fa[N][30],edg,deep[N];
int in[N],out[N],tot,flag[N];
void init()
{
    memset(in,0,sizeof(in));
    memset(deep,0,sizeof(deep));
    memset(head,-1,sizeof(head));
    edg=0;
    tot=0;
}
void add(int u,int v)
{
    edg++;
    edge[edg].v=v;
    edge[edg].next=head[u];
    head[u]=edg;
}
void dfs(int u,int fat)
{
    tot++;
    in[u]=tot;
    for (int i=1; i<=18 ;i++) {
        if(deep[u]<(1<<i)) break;
        fa[u][i] = fa[fa[u][i-1]][i-1];
    }
    for (int i=head[u];i!=-1;i=edge[i].next)
    {
        int v=edge[i].v;
        if(v==fat) continue;
        deep[v]=deep[u]+1;
        fa[v][0]=u;
        dfs(v,u);
    }
    out[u]=tot;
}
int RMQ_LCA(int x,int y) {
    if(deep[x]<deep[y]) swap(x,y);
    int d=deep[x]-deep[y];
    for (int i=0; i<=18 ;i++)
        if((1<<i)&d) x=fa[x][i];
    for (int i=18; i>=0 ;i--) {
        if(fa[x][i]!=fa[y][i]) {
            x=fa[x][i];y=fa[y][i];
        }
    }
    if(x==y) return x;
    else return fa[x][0];
}
int a[N],b[N];
int getpos(int x,int n)
{
    int p=lower_bound(b+1,b+1+n,x)-b;
    return p;
}
int main()
{
    int n,m;
    int le=1e5+10;
    while(~scanf("%d%d",&n,&m))
    {
        init();
        tree.init();
        tree.build(1,le,tree.rt[0]);
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]),b[i]=a[i];
        sort(b+1,b+1+n);
        for(int i=1;i<n;i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            add(u,v);
            add(v,u);
        }
        dfs(1,0);
        for(int i=1;i<=n;i++)
            flag[in[i]]=i;
        for(int i=1;i<=n;i++)
        {
            int p=getpos(a[flag[i]],n);
            //cout<<p<<" "<<in[fa[flag[i]][0]]<<endl;
            tree.update(p,1,tree.rt[in[fa[flag[i]][0]]],1,le,tree.rt[i]);
        }
        int ans=0;
        while(m--)
        {
            int u,v,k;
            scanf("%d%d%d",&u,&v,&k);
            u^=ans;
            int w=RMQ_LCA(u,v);
            ans=b[tree.query(tree.rt[in[w]],tree.rt[in[v]],tree.rt[in[fa[w][0]]],tree.rt[in[u]],1,le,k)];
            printf("%d",ans);
            if(m)
                printf("\n");
        }
    }
    return 0;
}
时间: 2024-10-23 21:25:31

bzoj 2588: Spoj 10628. Count on a tree LCA+主席树的相关文章

BZOJ 2588: Spoj 10628. Count on a tree [树上主席树]

2588: Spoj 10628. Count on a tree Time Limit: 12 Sec  Memory Limit: 128 MBSubmit: 5217  Solved: 1233[Submit][Status][Discuss] Description 给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权.其中lastans是上一个询问的答案,初始为0,即第一个询问的u是明文. Input 第一

BZOJ 2588: Spoj 10628. Count on a tree 主席树+lca

2588: Spoj 10628. Count on a tree Description 给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权.其中lastans是上一个询问的答案,初始为0,即第一个询问的u是明文. Input 第一行两个整数N,M. 第二行有N个整数,其中第i个整数表示点i的权值. 后面N-1行每行两个整数(x,y),表示点x到点y有一条边. 最后M行每行两个整数(u,v,k),表示一组询问.

BZOJ 2588: Spoj 10628. Count on a tree 树上跑主席树

2588: Spoj 10628. Count on a tree Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline/problem.php?id=2588 Description 给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权.其中lastans是上一个询问的答案,初始为0,即第一个询问的u是明文. Inp

bzoj 2588: Spoj 10628. Count on a tree

DFS序在树上建出主席树,然后..... 1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<cstdlib> 5 #include<cmath> 6 #include<algorithm> 7 #define ll long long 8 #define M 200009 9 using namespace std; 10 ll read()

SPOJ COT Count on a tree(主席树+倍增lca)

思路:这个题其实就是树上的第k小,主席树的本质还是类似于前缀和一样的结构,所以是完全相同的,所以我们在树上也可以用同样的方法,我们对于每一个节点进行建树,然后和普通的树上相同,ab之间的距离是等于 root[a]+root[b]-root[lca[a,b]]-root[fa[lca[a,b]]] 代码: 复制代码#include <bits/stdc++.h>using namespace std;const int maxn=1e5+7;const int POW=18;int num[ma

【BZOJ2588】Spoj 10628. Count on a tree 主席树+LCA

[BZOJ2588]Spoj 10628. Count on a tree Description 给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权.其中lastans是上一个询问的答案,初始为0,即第一个询问的u是明文. Input 第一行两个整数N,M. 第二行有N个整数,其中第i个整数表示点i的权值. 后面N-1行每行两个整数(x,y),表示点x到点y有一条边. 最后M行每行两个整数(u,v,k),表示一组

SPOJ 10628 Count on a tree(Tarjan离线LCA+主席树求树上第K小)

COT - Count on a tree #tree You are given a tree with N nodes.The tree nodes are numbered from 1 to N.Each node has an integer weight. We will ask you to perform the following operation: u v k : ask for the kth minimum weight on the path from node u 

bzoj2588: Spoj 10628. Count on a tree(树上第k大)(主席树)

每个节点继承父节点的树,则答案为query(root[x]+root[y]-root[lca(x,y)]-root[fa[lca(x,y)]]) #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<algorithm> using namespace std; const int maxn=100010; struct poi{int s

Spoj 10628. Count on a tree

Description 给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权.其中lastans是上一个询问的答案,初始为0,即第一个询问的u是明文. Input 第一行两个整数N,M. 第二行有N个整数,其中第i个整数表示点i的权值. 后面N-1行每行两个整数(x,y),表示点x到点y有一条边. 最后M行每行两个整数(u,v,k),表示一组询问. Output M行,表示每个询问的答案.最后一个询问不输出换行符 S