SPOJ COT 树上第K大(LCA+主席树)

转载请注明出处,谢谢http://blog.csdn.net/ACM_cxlove?viewmode=contents    by---cxlove

题目:给出一棵树,问两个节点之间路径经过的结点的权值的第k小的数。
http://www.spoj.com/problems/COT/ 
为了做这题,先去学了一下DFS+RMQ的LCA求法。

这题和普通的第K大类似。
普通的第K大,是从后往前建立主席树,前一个在后一个的基础上修改。
而树上第K大,依旧是每个结点一棵主席树,是在父节点的基础上修改。
那么可以发现这棵主席树是包括所有祖先结点的(就是深度在当前结点之上的)
查询的时候,是两个结点的值的和,还要减掉lca以上的部分。同时要注意处理lca这个 结点的值。
主要不同便是建树是根据父结点,以前查询的时候注意两个主席树的公共部分。

至于我写的效率略低啊,不加输入外挂会TLE。。。
SPOJ的运行速度,勉强卡过
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include
#include  
#include
#include  
#include
#define inf 1000000005  
#define M 10000005 
#define N 110005
#define maxn 210005  
#define eps 1e-8
#define zero(a) fabs(a)(b)?(a):(b))  
#define pb(a) push_back(a)  
#define mp(a,b) make_pair(a,b)  
#define mem(a,b) memset(a,b,sizeof(a))  
#define LL long long  
#define MOD 1000000007
#define sqr(a) ((a)*(a))  
#define Key_value ch[ch[root][1]][0]  
#define test puts("OK");  
#define pi acos(-1.0)
#define lowbit(x) ((-(x))&(x))
#define HASH1 1331
#define HASH2 10001
#define C   240  
#define vi vector
#define TIME 10  
#pragma comment(linker, "/STACK:1024000000,1024000000")  
using namespace std;
void scanf_(int &num){
    char in;  
    while((in=getchar())>'9'||in<'0'); 
    num=in-'0';   
    while(in=getchar(),in>='0'&&in<='9')   
        num*=10,num+=in-'0';
} 
int n,q,a[N];
vi edge[N];
/*              HASH部分            */
int t[N],m;
void Init_hash(){  
    for(int i=1;i<=n;i++)  
        t[i]=a[i];  
    sort(t+1,t+1+n);  
    m=unique(t+1,t+1+n)-t-1;  
}  
int hash(int x){  
    return lower_bound(t+1,t+1+m,x)-t;  
}  
/*              HASH部分             */
/*              主席树部分           */
int T[M],lson[M],rson[M],c[M],tot=0;
int bulid(int l,int r){
    int root=tot++;
    c[root]=0;
    if(l!=r){
        int mid=(l+r)>>1;
        lson[root]=bulid(l,mid);
        rson[root]=bulid(mid+1,r);
    }
    return root;
}
int update(int root,int pos,int val){
    int newroot=tot++,tmp=newroot;
    c[newroot]=c[root]+val;
    int l=1,r=m;
    while(l>1;
        if(pos<=mid){
            lson[newroot]=tot++;rson[newroot]=rson[root];  
            newroot=lson[newroot];root=lson[root];  
            r=mid;  
        }
        else{
            rson[newroot]=tot++;lson[newroot]=lson[root];  
            newroot=rson[newroot];root=rson[root];  
            l=mid+1;  
        }
        c[newroot]=c[root]+val;
    }
    return tmp;
}
int query(int left_root,int right_root,int LCA,int k){
    int lca_root=T[LCA],pos=hash(a[LCA]);
    int l=1,r=m;
    while(l>1;
        int t=c[lson[left_root]]+c[lson[right_root]]-2*c[lson[lca_root]]+(pos>=l&&pos<=mid);
        if(t>=k){
            left_root=lson[left_root];
            right_root=lson[right_root];
            lca_root=lson[lca_root];
            r=mid;
        }
        else{
            k-=t;
            left_root=rson[left_root];
            right_root=rson[right_root];
            lca_root=rson[lca_root];
            l=mid+1;
        }
    }
    return l;
}
/*              主席树部分           */
/*              LCA部分            */
int depth=0,b[N*2],cnt=0;
int p[N],f[N];
void dfs(int u,int pre){
    int t=++depth;
    b[++cnt]=t;
    f[t]=u;
    p[u]=cnt;
    T[u]=update(T[pre],hash(a[u]),1);
    for(int i=0;ip[b]) swap(a,b);
    return f[rmq(p[a],p[b])];
}
/*              LCA部分            */
int main(){
    scanf_(n);scanf_(q);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    for(int i=1;i


你可能感兴趣的:(ACM_数据结构)