• Spoj375 Qtree--树链剖分


    Spoj375 Qtree
    给一棵共有 n(n · 10000) 个结点的树, 每条边都有一个权值, 要求维护一个数据结构, 支持如下操作:
    1. 修改某条边的权值;
    2. 询问某两个结点之间的唯一通路上的最大边权.
    其中操作的总次数为 q.
    Sample Input
    3
    1 2 1
    2 3 2
    QUERY 1 2
    CHANGE 1 3
    QUERY 1 2
    DONE
    Sample Output
    1
    3

    #include<cstdio>
    #include<algorithm>
    #include<cstring> 
    using namespace std;
    int sum,maxx,n,m,f[30001],pre[100001],nxt[100001],h[30001],now,size[100001],dep[100001],id[30001],top[30001],cnt,y[30001],z[30001],x[30001];
    struct oo
    {
    	int a,b,mx;
    }
    s[100001];
    char p[9];
    void dfs(int x)
    {
        size[x]=1;
        for(int i=h[x];i;i=nxt[i])
        {
            if(pre[i]==f[x])
    		   continue;
            dep[pre[i]]=dep[x]+1;
            f[pre[i]]=x;
            dfs(pre[i]);
            size[x]+=size[pre[i]];
        }
    }
    void dfs2(int x,int f)
    {
        int k=0;
        id[x]=++cnt;//x在线段树中的位置 
        top[x]=f;//标记top结记 
        for(int i=h[x];i;i=nxt[i]) // 找出重儿子 
            if(size[pre[i]]>size[k]&&dep[pre[i]]>dep[x])
    		   k=pre[i];
        if(!k)
    	    return ;
        dfs2(k,f);
        for(int i=h[x];i;i=nxt[i])
            if(dep[pre[i]]>dep[x]&&pre[i]!=k)
                dfs2(pre[i],pre[i]);
    }
    void ins(int x,int y)
    {
        pre[++now]=y;
        nxt[now]=h[x];
        h[x]=now;
    }
    void build(int x,int l,int r)
    {
        s[x].a=l;
    	s[x].b=r;
        if(l==r)
    	 {
    			s[x].mx=-1e9;
    			return ;
    	 }
        build(x<<1,l,l+r>>1);
        build(x<<1|1,(l+r>>1)+1,r);
        s[x].mx=max(s[x<<1].mx,s[x<<1|1].mx);
    }
    void get(int x,int l,int r)
    {
        if(s[x].a>=l&&r>=s[x].b)
            maxx=max(s[x].mx,maxx);
        else
        {
            int mid=s[x].a+s[x].b>>1;
            if(l<=mid)
    		    get(x<<1,l,r);
            if(r>mid)
    		    get(x<<1|1,l,r);
        }
    }
    void qmax(int x,int y)
    {
        maxx=-1e9;
        while(top[x]!=top[y])//当没有在一条重链上时 
        {
            if(dep[top[x]]<dep[top[y]])
    		   swap(x,y);
            get(1,id[top[x]],id[x]);
            x=f[top[x]];
        }
        if(id[x]>id[y])
    	    swap(x,y);
        get(1,id[x]+1,id[y]);
    }
    void change(int x,int l,int v)
    {
        if(s[x].a==s[x].b)
        {
            s[x].mx=v;
            return ;
        }
        int mid=s[x].a+s[x].b>>1;
        if(l<=mid)
    	    change(x<<1,l,v);
        else 
    	    change(x<<1|1,l,v);
        s[x].mx=max(s[x<<1].mx,s[x<<1|1].mx);
    }
    int T;
    int main()
    {
        scanf("%d",&T);
        while(T--)
        {
            scanf("%d",&n);
            memset(h,0,sizeof h);
            now=0;cnt=0;
            for(int i=1;i<n;i++)
            {
                scanf("%d%d%d",&x[i],&y[i],&z[i]);
                ins(x[i],y[i]);
    			ins(y[i],x[i]);
            }
            dfs(1);
    		dfs2(1,1); 
            build(1,1,n);
            for(int i=1;i<n;i++)
            {
                int a=id[x[i]],b=id[y[i]];
                if(dep[x[i]]>dep[y[i]])
                //将边权放到点上,要放到这条边的儿子点上
    			//因为某个点可以会有多个子结点,放父亲点,就会出问题了 
    			   change(1,a,z[i]),z[i]=a;//记下第i条边在线段树中的位置 
    			 
                else 
    			   change(1,b,z[i]),z[i]=b;
            }
            while(1)
            {
                int a,b;
                scanf("%s",p+1);
                if(p[1]=='Q')
                {
                    scanf("%d%d",&a,&b);
                    qmax(a,b);
                    printf("%d
    ",maxx);
                } 
                if(p[1]=='D')break;
                if(p[1]=='C')
                    scanf("%d%d",&a,&b),change(1,z[a],b);
            }
        }
    }
    

      

  • 相关阅读:
    Objective-C中#define的常见用法
    OpenGL ES为缓存提供数据的7个步骤
    绕指定点旋转算法
    矩阵平移旋转缩放公式
    矩阵和向量的乘法顺序
    干货集合
    RGB颜色空间与YCbCr颜色空间的互转
    UINavi中push控制器的时候隐藏TabBar
    CZLayer的阴影
    CALayer初认识
  • 原文地址:https://www.cnblogs.com/cutemush/p/11853399.html
Copyright © 2020-2023  润新知