zoukankan      html  css  js  c++  java
  • 【刷题】BZOJ 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),表示一组询问。

    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

    N,M<=100000

    Solution

    一个典型的树上差分,然后维护第(k)大。。主席树嘛
    我们主席树的每个版本是从它的父亲处继承过来的,那么它维护的就是这个节点到根节点路径上的信息
    那么我们的差分就是

    [ans=find(T_{u}+T_{v}-T_{lca}-T_{lca'fa}) ]

    查询就在这个差分后的树上找就行了

    #include<bits/stdc++.h>
    #define ll long long
    #define db double
    #define ld long double
    #define Mid ((l+r)>>1)
    #define lson l,Mid
    #define rson Mid+1,r
    const int MAXN=100000+10;
    int n,m,A[MAXN],Jie[MAXN][20],dep[MAXN],e,beg[MAXN],nex[MAXN<<1],to[MAXN<<1],ans;
    std::vector<int> V;
    std::map<int,int> M;
    struct ChairMan_Tree{
        int cnt,lc[MAXN<<5],rc[MAXN<<5],sum[MAXN<<5],root[MAXN];
    	inline void init()
    	{
    		cnt=0;
    		memset(lc,0,sizeof(lc));
    		memset(rc,0,sizeof(rc));
    		memset(sum,0,sizeof(sum));
    	}
        inline void Build(int &rt,int l,int r)
        {
            rt=++cnt;
            sum[rt]=0;
            if(l==r)return ;
            Build(lc[rt],lson);
            Build(rc[rt],rson);
        }
        inline void Insert(int &rt,int l,int r,int last,int pos)
        {
            rt=++cnt;
            sum[rt]=sum[last]+1;
            lc[rt]=lc[last];
            rc[rt]=rc[last];
            if(l==r)return ;
            else
            {
    			if(pos<=Mid)Insert(lc[rt],lson,lc[last],pos);
    			else Insert(rc[rt],rson,rc[last],pos);
            }
        }
    	inline int Query(int left,int right,int gfa,int grand,int l,int r,int k)
    	{
    		if(l==r)return l;
    		else
    		{
    			int t=sum[lc[left]]+sum[lc[right]]-sum[lc[gfa]]-sum[lc[grand]];
    			if(k<=t)return Query(lc[left],lc[right],lc[gfa],lc[grand],lson,k);
    			else return Query(rc[left],rc[right],rc[gfa],rc[grand],rson,k-t);
    		}
    	}
    };
    ChairMan_Tree T;
    template<typename T> inline void read(T &x)
    {
        T data=0,w=1;
        char ch=0;
        while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
        if(ch=='-')w=-1,ch=getchar();
        while(ch>='0'&&ch<='9')data=((T)data<<3)+((T)data<<1)+(ch^'0'),ch=getchar();
        x=data*w;
    }
    template<typename T> inline void write(T x,char c='')
    {
        if(x<0)putchar('-'),x=-x;
        if(x>9)write(x/10);
        putchar(x%10+'0');
        if(c!='')putchar(c);
    }
    template<typename T> inline void chkmin(T &x,T y){x=(y<x?y:x);}
    template<typename T> inline void chkmax(T &x,T y){x=(y>x?y:x);}
    template<typename T> inline T min(T x,T y){return x<y?x:y;}
    template<typename T> inline T max(T x,T y){return x>y?x:y;}
    inline void insert(int x,int y)
    {
        to[++e]=y;
        nex[e]=beg[x];
        beg[x]=e;
    }
    inline void discre()
    {
        sort(V.begin(),V.end());
        V.erase(unique(V.begin(),V.end()),V.end());
        for(register int i=1;i<=n;++i)
        {
            int pre=A[i];
            A[i]=lower_bound(V.begin(),V.end(),A[i])-V.begin()+1;
            M[A[i]]=pre;
        }
    }
    inline void dfs(int x,int f,int d)
    {
    	T.Insert(T.root[x],1,n,T.root[f],A[x]);
    	dep[x]=d;
    	Jie[x][0]=f;
    	for(register int i=beg[x];i;i=nex[i])
    		if(to[i]==f)continue;
    		else dfs(to[i],x,d+1);
    }
    inline void init()
    {
    	for(register int j=1;j<20;++j)
    		for(register int i=1;i<=n;++i)Jie[i][j]=Jie[Jie[i][j-1]][j-1];
    }
    inline int LCA(int u,int v)
    {
    	if(dep[u]<dep[v])std::swap(u,v);
    	if(dep[u]>dep[v])
    		for(register int i=19;i>=0;--i)
    			if(dep[Jie[u][i]]>=dep[v])u=Jie[u][i];
    	if(u==v)return u;
    	for(register int i=19;i>=0;--i)
    		if(Jie[u][i]!=Jie[v][i])u=Jie[u][i],v=Jie[v][i];
    	return Jie[u][0];
    }
    int main()
    {
        read(n);read(m);
        for(register int i=1;i<=n;++i)
        {
            read(A[i]);
            V.push_back(A[i]);
        }
        discre();
        for(register int i=1;i<n;++i)
        {
            int u,v;
            read(u);read(v);
            insert(u,v);
            insert(v,u);
        }
    	T.init();
    	T.Build(T.root[0],1,n);
    	dfs(1,0,1);
    	init();
        while(m--)
        {
            int u,v,k,lca;
            read(u);read(v);read(k);
            u^=ans;
    		lca=LCA(u,v);
            ans=M[T.Query(T.root[u],T.root[v],T.root[Jie[lca][0]],T.root[lca],1,n,k)];
    		write(ans,'
    ');
        }
        return 0;
    }
    
    
  • 相关阅读:
    Swift 高级运算符
    drawer navigation, tabhostFragment 默认导向
    Jquery easyUI datagrid载入复杂JSON数据方法
    逆向project第005篇:跨越CM4验证机制的鸿沟(下)
    据说有99%的人都会做错的面试题
    POJ3187 Backward Digit Sums 【暴搜】
    Android
    arm-linux-gcc 的使用
    GNU 交叉工具链的介绍与使用
    使用当前平台的 gcc 编译内核头文件
  • 原文地址:https://www.cnblogs.com/hongyj/p/8619509.html
Copyright © 2011-2022 走看看