POJ 3237 树链剖分

这个知识点学了4天,有两天的时间都在调试这个代码,发现自己写的还是少,发现了好多的bug,和很神奇的事情发生,比如写个递归忘了写return,还有好多。

树链剖分:按照某个规则对树进行划分,而现在这个是按照轻重链对树进行划分。    
概念:
重儿子:对于结点v来说他的儿子里面孙子最多的一个。                                        
重链  :v与他的重儿子的连边。                                                           
top[] :与v在同一重链上的根节点。                         
ti[]  :当前边在线椴树中的位置。
dep[] :结点的深度。
siz[] : 结点的儿子个数。                                                                
father[]:结点的父亲。                                                            
son[] : 结点的儿子。                                                                       
流程:按照这种划分把边分别都安排了顺序,那么在改变边值的时候,就可以用到线段树的知识了。
复杂度分析:这个不是很理解,不过可以和线段树那样的复杂度解决这个问题,轻链直接更新,重链线段树维护

#include<iostream>
#include<cstring>
#include<algorithm>
#define lson id << 1
#define rson id << 1|1
#include<cstdio>
using namespace std;
const int M = 10008;
int father[M],dep[M],top[M],siz[M],ti[M],son[M];
int idx,tp = 0;
const int Inf = 0x3ffff;
struct line_tree{
    int l,r,Max,Min,mark;
    int mid(){
        return (l+r)/2;
    }
}node[M*100];
struct {
    int head;
}H[M];
struct{
    int v,next;
}E[M*100];
void add(int u,int v){
    E[tp].v =  v;
    E[tp].next = H[u].head;
    H[u].head = tp++;
}
void init(){
    memset(E,-1,sizeof(E));
    memset(H,-1,sizeof(H));
    tp = 0;idx = 0;
    memset(son,0,sizeof(son));
    memset(top,0,sizeof(top));

}
void dfs_1(int u,int fa){
    son[u] = 0;siz[u] = 1;dep[u] = dep[fa] + 1; father[u] = fa;
    for(int i=H[u].head;i!=-1;i=E[i].next){
        int v = E[i].v;
        if(v == fa)continue;
        dfs_1(v,u);
        siz[u] += siz[v];
        if(siz[v] > siz[son[u]]) son[u] = v;
    }
}

void dfs_2(int u,int fa){
    top[u] = fa;
    ti[u] = idx++;
    if(son[u])dfs_2(son[u],fa);
    for(int i=H[u].head;i!=-1;i=E[i].next){
        int v = E[i].v;
        if(v == father[u]||v == son[u])continue;
        dfs_2(v,v);
    }
}
/* 线段树*/

void  build_tree(int id,int l,int r){
    node[id].l = l;node[id].r = r;node[id].mark = 0;
    node[id].Max = node[id].Min = 0;
    if(l == r)return;
    int mid = node[id].mid();
    build_tree(lson,l,mid);
    build_tree(rson,mid+1,r);
}
void push_down(int id){
    if(node[id].l == node[id].r)return;
    if(node[id].mark){

        node[lson].Max = -node[lson].Max;
        node[lson].Min = -node[lson].Min;
        swap(node[lson].Max,node[lson].Min);
        node[rson].Max = -node[rson].Max; // 妈的,大意了调试了1天
        node[rson].Min = -node[rson].Min;
        swap(node[rson].Max,node[rson].Min);
        node[lson].mark ^= 1;
        node[rson].mark ^= 1;
        node[id].mark = 0;
    }
}
void push_up(int id){
    node[id].Max = max(node[lson].Max,node[rson].Max);
    node[id].Min = min(node[lson].Min,node[rson].Min);
}
bool  flag = false;
void  update(int id,int k,int w){

    if(node[id].l == k&&node[id].r == k){
       node[id].Max = node[id].Min = w;
       return;
    }
    push_down(id);
    int mid = node[id].mid();
    if(k <= mid)update(lson,k,w);
    else update(rson,k,w);
    push_up(id);
}
void nede(int id,int l,int r){

    if(node[id].l == l&&node[id].r == r){

        node[id].Max = -node[id].Max;
        node[id].Min = -node[id].Min;
        swap(node[id].Max,node[id].Min); 
        node[id].mark ^= 1;
        return;
    }
    push_down(id);
    int mid = node[id].mid();
    if(r <=mid)nede(lson,l,r);
    else if(l > mid)nede(rson,l,r);
    else{
        nede(lson,l,mid);
        nede(rson,mid+1,r);
    }
    push_up(id);
}
int ans = 0;
int query(int id,int l,int r){

    if( node[id].l == l&&node[id].r == r)return node[id].Max;
    push_down(id);
    int mid= node[id].mid();
    if(r <=mid)return query(lson,l,r);
    else if(l > mid)return query(rson,l,r);
    else return max( query(lson,l,mid),query(rson,mid+1,r));
    push_up(id);
}
int findMax(int u,int v){
    int f1 = top[u];
    int f2 = top[v];
    int mmax = -Inf;
    while(f1 !=f2){
        if(dep[f1] < dep[f2]){
            swap(f1,f2);
            swap(u,v);
        }
        mmax = max(mmax,query(1,ti[f1],ti[u]));
        u = father[f1];f1 = top[u];
    }

    if(u == v)return mmax;
    if(dep[u] > dep[v])swap(u,v);
    mmax =  max(mmax,query(1,ti[son[u]],ti[v]));
    return mmax;
}
void negat(int u,int v){
    int f1 = top[u];
    int f2 = top[v];

    while(f1 != f2){
        if(dep[f1] < dep[f2]){
            swap(f1,f2);
            swap(u,v);
        }
        nede(1,ti[f1],ti[u]);
        u = father[f1];f1 = top[u];
    }
    if(u == v)return;
    if(dep[u] > dep[v])swap(u,v);
    nede(1,ti[son[u]],ti[v]);
}
int e[M][3];
int main(){
    int n,m;
    int T;
    scanf("%d",&T);
    while(T--){
        init();
        scanf("%d",&n);
        for(int i=0;i<n-1;i++){
            scanf("%d%d%d",&e[i][0],&e[i][1],&e[i][2]);
            add(e[i][0],e[i][1]);
            add(e[i][1],e[i][0]);
        }
        dfs_1(1,1);
        dfs_2(1,1);
        build_tree(1,1,idx-1);
        for(int i=0;i<n-1;i++){
            if(dep[e[i][0]] > dep[e[i][1]])
                swap(e[i][0],e[i][1]);
                update(1,ti[e[i][1]],e[i][2]);
        }
        char str[100];
        int u,v;
        while(scanf("%s",str) == 1){
            if(str[0] == 'D')break;
            scanf("%d%d",&u,&v);
          //  cout <<"ti-->" <<ti[u] << "tiv-->"<<ti[v] <<endl;
            if(str[0] == 'Q') printf("%d\n",findMax(u,v));
            else if(str[0] == 'C') update(1,ti[e[u-1][1]],v);
            else 
                    negat(u,v);
        }
    }

}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值