【板子】树链剖分

    安利几份学习笔记
    树链剖分 树链剖分(轻重链剖分)算法笔记
    然后上一道例题: Spoj 375

I Think

    题意:带修改树上两点最大路径

Code

#include
#include
using namespace std;
const int sm = 1e4+10;
char inst[10];
int n,a,b,cnt,tot,T,mx[sm<<2];
int to[sm<<1],hd[sm<<1],nxt[sm<<1],e[sm][3];
int w[sm],sz[sm],Fa[sm],son[sm],dep[sm],top[sm];
//top[i]记点i所在重链的顶端点
void Swap(int &x,int &y) { int t=x;x=y;y=t; }
int Max(int x,int y) { return x>y?x:y; }
void read(int &x) {
    char ch=getchar();x=0;
    while(ch>'9'||ch<'0') ch=getchar();
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
}
void Add(int f,int t) {
    to[++tot]=t,nxt[tot]=hd[f],hd[f]=tot;
    to[++tot]=f,nxt[tot]=hd[t],hd[t]=tot;
}
void Dfsa(int x,int fa) { //处理出dep[] Fa[] son[] sz[]
    dep[x]=dep[fa]+1,Fa[x]=fa,sz[x]=1,son[x]=0;
    for(int i=hd[x];i;i=nxt[i])
        if(to[i]!=fa) {
            Dfsa(to[i],x),sz[x]+=sz[to[i]];
            if(sz[son[x]]void Dfsb(int x,int tp) { //处理出top[]-重链的链顶端 w[i]-第i个点与其父节点连边的编号
    w[x]=++tot,top[x]=tp;
    if(son[x]) Dfsb(son[x],top[x]);//使重边编号连续
    for(int i=hd[x];i;i=nxt[i])
        if(to[i]!=Fa[x]&&to[i]!=son[x]) 
            Dfsb(to[i],to[i]);
}
void Modify(int rt,int l,int r,int p,int val) {
    if(l==r) { mx[rt]=val;return;}
    int m=(l+r)>>1;
    if(p<=m) Modify(rt<<1,l,m,p,val);
    else Modify(rt<<1|1,m+1,r,p,val);
    mx[rt]=Max(mx[rt<<1],mx[rt<<1|1]);
}
int Maxn(int rt,int l,int r,int a,int b) {
    if(a<=l&&r<=b) return mx[rt];
    int m=(l+r)>>1,ans=0;
    if(a<=m) ans=Max(ans,Maxn(rt<<1,l,m,a,b));
    if(b> m) ans=Max(ans,Maxn(rt<<1|1,m+1,r,a,b));
    return ans;
}
int Query(int a,int b) {
    int f1=top[a],f2=top[b],tmp=0;
    while(f1!=f2) {
        if(dep[f1]//别忘了swap(a,b)
        tmp=Max(tmp,Maxn(1,1,tot,w[f1],w[a]));//注意w[f1]
        a=Fa[f1],f1=top[a];
        //f1与其父节点连边已在上一步中比较过 因此直接将a跳至Fa[f1]
    }
    if(a==b) return tmp;
    if(dep[a]1,1,tot,w[son[b]],w[a]));//不要漏son[] 因为边权会放在下面的点上
    return tmp;
}
int main() {
    scanf("%d",&T);
    while(T--) {
        read(n);
        tot=0,memset(hd,0,sizeof(hd));
        for(int i=1;i0]),read(e[i][1]),read(e[i][2]);
            Add(e[i][0],e[i][1]);
        }
        tot=0,Dfsa(1,0),Dfsb(1,1);//两遍dfs完成预处理
        for(int i=1;iif(dep[e[i][0]]1]])
                Swap(e[i][0],e[i][1]);
            Modify(1,1,tot,w[e[i][0]],e[i][2]);
        }
        while(scanf("%s",inst)!=EOF) {
            if(inst[0]=='D') break;
            scanf("%d%d\n",&a,&b);
            if(inst[0]=='C') Modify(1,1,tot,w[e[a][0]],b);
            else printf("%d\n",Query(a,b));
        }   
    }   
    return 0;
}

你可能感兴趣的:(线段树,树链剖分,小板子)