URAL1553 Caves and Tunnels 树链剖分 动态树

URAL1553 维护一棵树,随时修改某个节点的权值,询问(x,y)路径上权值最大的点。

树是静态的,不过套动态树也能过,时限卡的严就得上树链剖分了。

还是那句话 splay的核心是splay(x) LCT的核心是access(x)

SPOJ OTOCI的代码改了两行就过了

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int MaxNode=131000;

int Lch[MaxNode];
int Rch[MaxNode];
int Pnt[MaxNode];
int Data[MaxNode];
int Sum[MaxNode];
int Rev[MaxNode];
int List[MaxNode];
int maxv[MaxNode];
int Total;

inline bool isRoot(int t){
    return (!Pnt[t]||(Lch[Pnt[t]]!=t&&Rch[Pnt[t]]!=t));
}
inline void Update(int cur){
    maxv[cur]=Data[cur];
    if(Lch[cur]!=0)maxv[cur]=max(maxv[cur],maxv[Lch[cur]]);
    if(Rch[cur]!=0)maxv[cur]=max(maxv[cur],maxv[Rch[cur]]);
}
void Reverse(int cur){
    if (!Rev[cur]) return;
    swap(Lch[cur],Rch[cur]);
    Rev[Lch[cur]]^=1;
    Rev[Rch[cur]]^=1;
    Rev[cur]=0;
}
void LeftRotate(int cur){
    if (isRoot(cur)) return;
    int pnt=Pnt[cur],anc=Pnt[pnt];
    Lch[pnt]=Rch[cur];
    if (Rch[cur]) Pnt[Rch[cur]]=pnt;
    Rch[cur]=pnt;
    Pnt[pnt]=cur;
    Pnt[cur]=anc;
    if (anc){
        if (Lch[anc]==pnt) Lch[anc]=cur;
        else if (Rch[anc]==pnt) Rch[anc]=cur;
    }
    Update(pnt);
    Update(cur);
}
void RightRotate(int cur){
    if (isRoot(cur)) return;
    int pnt=Pnt[cur],anc=Pnt[pnt];
    Rch[pnt]=Lch[cur];
    if (Lch[cur]) Pnt[Lch[cur]]=pnt;
    Lch[cur]=pnt;
    Pnt[pnt]=cur;
    Pnt[cur]=anc;
    if (anc){
        if (Rch[anc]==pnt) Rch[anc]=cur;
        else if (Lch[anc]==pnt) Lch[anc]=cur;
    }
    Update(pnt);
    Update(cur);
}
void Splay(int cur){
    int pnt,anc;
    List[++Total]=cur;
    for (int i=cur;!isRoot(i);i=Pnt[i]) List[++Total]=Pnt[i];
    for (;Total;--Total)
        if (Rev[List[Total]]) Reverse(List[Total]);
    while (!isRoot(cur)){
        pnt=Pnt[cur];
        if (isRoot(pnt)){// 父亲是根结点,做一次旋转
            if (Lch[pnt]==cur) LeftRotate(cur);
            else RightRotate(cur);
        }
        else{
            anc=Pnt[pnt];
            if (Lch[anc]==pnt){
                if (Lch[pnt]==cur) LeftRotate(pnt),LeftRotate(cur);// 一条线
                else RightRotate(cur),LeftRotate(cur);// 相反两次
            }
            else{
                if (Rch[pnt]==cur) RightRotate(pnt),RightRotate(cur);// 一条线
                else LeftRotate(cur),RightRotate(cur);// 相反两次
            }
        }
    }
}
int Expose(int u){
    int v=0;
    for (;u;u=Pnt[u]) Splay(u),Rch[u]=v,v=u,Update(u);
    for (;Lch[v];v=Lch[v]);
    return v;
}
void Modify(int x,int d){
    Splay(x);
    Data[x]=d;
    Update(x);
}
int Query(int x,int y){
    int rx=Expose(x),ry=Expose(y);
    if (rx==ry){
        for (int u=x,v=0;u;u=Pnt[u]){
            Splay(u);
            if (!Pnt[u]) return max(max(maxv[Rch[u]],Data[u]),maxv[v]);
            Rch[u]=v;
            Update(u);
            v=u;
        }
    }
    return -1;
}
bool Join(int x,int y){
    int rx=Expose(x),ry=Expose(y);
    if (rx==ry) return false;
    else{
        Splay(x);
        Rch[x]=0;
        Rev[x]=1;
        Pnt[x]=y;
        Update(x);
        return true;
    }
}
void Cut(int x){
    if (Pnt[x]){
        Expose(x);
        Pnt[Lch[x]]=0;
        Lch[x]=0;
        Update(x);
    }
}
int n,Q;

void init(){
    Total=0;
    memset(Rev,0,sizeof(Rev));
    memset(Pnt,0,sizeof(Pnt));
    memset(Lch,0,sizeof(Lch));
    memset(Rch,0,sizeof(Rch));
    memset(Sum,0,sizeof(Sum));
    memset(Data,0,sizeof(Data));
    memset(maxv,0,sizeof(maxv));
}
char cmd[22];
int main()
{   freopen("t.txt","r",stdin);
    init();
    scanf("%d",&n);
    for(int i=0;i<n-1;i++)
    	{
    	 int a,b;
    	 scanf("%d%d",&a,&b);
    	 Join(a,b);
		}
    scanf("%d",&Q);
    while (Q--){
        int x,y;
        scanf("%s%d%d",cmd,&x,&y);
        if (cmd[0]=='I'){
            Modify(x,Data[x]+y);
        }
        if (cmd[0]=='G'){
            printf("%d",Query(x,y));
            if(Q>0)printf("\n");
        }

        
    }
    return 0;
}

  

转载于:https://www.cnblogs.com/heisenberg-/p/6597097.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值