zoukankan      html  css  js  c++  java
  • HDU 3966 & POJ 3237 & HYSBZ 2243 & HRBUST 2064 树链剖分

    树链剖分是一个很固定的套路 一般用来解决树上两点之间的路径更改与查询 

    思想是将一棵树分成不想交的几条链 并且由于dfs的顺序性 给每条链上的点或边标的号必定是连着的 那么每两个点之间的路径都可以拆成几条链 那么就是对一群区间进行更改 这时候基本是用线段树进行logn的操作

    做了三道基础题 都属于比较好想的 也就是线段树比较麻烦 需要写相当长一段时间...

    HDU 3966

    给出一棵树的连接状况和边的大小 每次可以对a-b的路径的边的权值取反 或者改变指定边的值 或者求a-b路径的最大值

    每次取反 最大值就是原最小值*-1 这样维护下去就好

    POJ 3237 

    给出一棵树的连接状况和点的初始值 每次对a-b的路径上的点权进行加减 询问单点大小

    树状数组会超时 只能用线段树...需要注意的是点权和边权在树链剖分的时候会有一点不同 例如 u == v  是否return 等

    HYSBZ 2243

    总觉得以前见过的样子..

    给出一棵树的连接状况和边的初始颜色 每次可以对a-b的路径上的边进行更改颜色

    最后求a-b路径上的颜色段个数

    可以由线段树的本质来看 每个区间的两个子区间 都是从这个线段树一分为2

    那么 一个区间内有多少个颜色段数 就等于他的两个子区间的颜色加起来 如果子区间相邻的点颜色相同 那么久减去一

    可以在tr数组中记录这个区间的mlmr 即中点两边的点的颜色

    每次记录下来前一条链的尾颜色 和当前链的头颜色进行对比 如果相同 就减一

    最后当f1 == f2的时候 要同时对比ys1和ys2 

    交换uv的时候 ys1和ys2也需要交换 

    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    #include<math.h>
    #include<map>
    #include<iostream>
    #include<string>
    #include<vector>
    using namespace std;
    #define L long long
    
    vector<int >q[100050];
    
    int p[100050];
    int fp[100050];
    int fa[100050];
    int son[100050];
    int deep[100050];
    int top[100050];
    int num[100050];
    int n , m , pp;
    int pos;
    void init(){
        for(int i= 1;i<=n;i++){
            q[i].clear();
        }
        memset(son , -1 ,sizeof(son));
        pos = 0;
    }
    int in[100050];
    void dfs(int u , int pre , int d){
        deep[u] = d;
        fa[u] = pre;
        num[u] = 1;
        for(int i = 0;i<q[u].size();i++){
            int v = q[u][i];
            if(v != pre){
                dfs(v,u,d+1);
                num[u] += num[v];
                if(son[u] == -1 || num[v] > num[son[u]]){
                    son[u] = v;
                }
            }
        }
    }
    
    void dfs2(int u , int zx){
        top[u] = zx;
        p[u] = pos ++;
        fp[pos - 1] = u;
        if(son[u] == -1){
            return ;
        }
        dfs2(son[u],zx);
        for(int i = 0;i<q[u].size();i++){
            int v = q[u][i];
            if(v != fa[u] && v != son[u]){
                dfs2(v,v);
            }
        }
    }
    /**
    线段树 1求一个区间内有多少个颜色 2求一个点的颜色
    2直接写查询
    1记录这个区间的 中间的两个的颜色
    */
    struct node{
        int l,r;
        int ml;
        int mr;
        int ll ;
        int rr ;
        int mark;
        int d;
    }tr[100050 * 4];
    void pushup(int i){
        if(tr[i].l == tr[i].r)
            return ;
        tr[i].ll = tr[i<<1].ll;
        tr[i].rr = tr[(i<<1)|1].rr ;
        tr[i].ml = tr[i<<1].rr;
        tr[i].mr = tr[(i<<1)|1].ll ;
        tr[i].d = tr[i<<1].d + tr[(i<<1)|1].d ;
        if(tr[i<<1].rr == tr[(i<<1)|1].ll)
            tr[i].d -- ;
    }
    void pushdown(int i){
        if(tr[i].l == tr[i].r)return ;
        if(tr[i].mark != 0){
            tr[i<<1].mark = tr[(i<<1)|1].mark = tr[i].mark ;
            tr[i<<1].ll = tr[i<<1].rr = tr[i<<1].ml = tr[i<<1].mr = tr[i].mark;
            tr[(i<<1)|1].ll = tr[(i<<1)|1].rr = tr[(i<<1)|1].ml = tr[(i<<1)|1].mr = tr[i].mark;
            tr[i<<1].d= tr[(i<<1)|1].d = 1;
            tr[i].mark = 0;
        }
    }
    void crea(int i , int l , int r){
        tr[i].l = l ;
        tr[i].r = r;
        tr[i].ml = tr[i].mr = tr[i].ll = tr[i].rr = tr[i].mark = 0;
        if(l == r){
            tr[i].ml = tr[i].mr = tr[i].ll = tr[i].rr = in[fp[l]];
            tr[i].d = 1;
            return ;
        }
        int mid = (l + r )/ 2;
        crea(i<<1,l,mid);
        crea((i<<1)|1,mid+1,r);
        pushup(i);
    }
    int res ;
    void upda(int i ,int l ,int r , int c){
        if(tr[i].l ==l && r == tr[i].r){
            tr[i].ml = tr[i].mr = tr[i].ll = tr[i].rr = tr[i].mark = c;
            tr[i].d = 1;
            return ;
        }
        pushdown(i);
        int mid = (tr[i].l + tr[i].r) / 2;
        if(r <= mid){
            upda(i<<1,l,r,c);
        }
        else if(l > mid){
            upda((i<<1)|1,l,r,c);
        }
        else {
            upda(i<<1,l,mid,c);
            upda((i<<1)|1,mid+1,r,c);
        }
        pushup(i);
    }
    int query(int i ,int l ,int r){
        if(tr[i].l == l && r == tr[i].r){
            return tr[i].d;
        }
        pushdown(i);
        int mid = (tr[i].l + tr[i].r) / 2;
        if(r <= mid){
            return query(i<<1,l,r);
        }
        else if(l > mid){
            return query((i<<1)|1,l,r);
        }
        else {
            if(tr[i].ml == tr[i].mr){
                return query(i<<1,l,mid) + query((i<<1)|1,mid+1,r) - 1;
            }
            else {
                return query(i<<1,l,mid) + query((i<<1)|1,mid+1,r);
            }
        }
    }
    int qu2(int i ,int pos){
        if(tr[i].l == tr[i].r){
            return tr[i].ml ;
        }
        pushdown(i);
        int mid = (tr[i].l + tr[i].r) / 2;
        if(pos <= mid){
            return qu2(i<<1,pos);
        }
        else {
            return qu2((i<<1)|1,pos);
        }
    }
    void did(int u , int v, int c){
        int f1 = top[u];
        int f2 = top[v];
        while(f1 != f2){
            if(deep[f1] < deep[f2]){
                swap(f1,f2);
                swap(u,v);
            }
            upda(1,p[f1],p[u],c);
            u = fa[f1];
            f1 = top[u];
        }
        if(deep[u] < deep[v]){
            swap(u,v);
        }
        upda(1,p[v],p[u],c);
    }
    int slpf(int u, int v){
        int ans = 0;
        int f1 = top[u];
        int f2 = top[v];
        int ys1 = -1;
        int ys2 = -1;
        while(f1 != f2){
            if(deep[f1] < deep[f2]){
                swap(u,v);
                swap(f1,f2);
                swap(ys1,ys2);
            }
            ans += query(1,p[f1],p[u]);
            if(ys1 == qu2(1,p[u])){
                ans -- ;
            }
            ys1 = qu2(1,p[f1]);
            u = fa[f1];
            f1 = top[u];
            //printf("%d
    ",ans);
        }
        if(deep[u] < deep[v]){
            swap(u,v);
            swap(ys1,ys2); /// --------
        }
        ans += query(1,p[v],p[u]);
        if(ys1==qu2(1,p[u])){
            ans -- ;
        }
        if(ys2==qu2(1,p[v])){
            ans -- ;
        }
    
        return ans ;
    }
    int main(){
        //freopen("in.cpp","r",stdin);
        while(scanf("%d%d",&n,&pp)!=EOF){
            init();
            for(int i=1;i<=n;i++){
                scanf("%d",&in[i]);
            }
    
            for(int i=1;i<=n-1;i++){
                int u , v;
                scanf("%d%d",&u,&v);
                q[u].push_back(v);
                q[v].push_back(u);
            }
            dfs(1,0,0);
            dfs2(1,1);
            crea(1,0,pos-1);
            for(int i=1;i<=pp;i++){
                char s[20];
                scanf("%s",s);
                if(s[0] == 'C'){
                    int u , v, c;
                    scanf("%d%d%d",&u,&v,&c);
                    did(u,v,c);
                }
                else {
                    int u,v;
                    scanf("%d%d",&u,&v);
                    printf("%d
    ",slpf(u,v));
                }
            }
        }
    }
    

    感觉树链剖分的主要难点在于线段树的构造...

    2017.3.18 很久后又做了一道树链剖分 当然LCA也可做

    询问树上路径可否组成三角形 利用斐波那契的思想 由于每一条路径的len<=1e9 所以当路径的条数超过64左右的时候肯定是可以的

    当小于64的时候拿出来直接暴力就可以了

    树链剖分中 u与top[u] 是连着的 在这里 用a[u]存放 u到fa[u] 的边的权值 

    所以top[u] -> fa[top[u]] 其实是不在 u -> f1 这条链上的 但是之后会发生 u = fa[f1] 直接翻到这条边上去

    所以如果top[u] -> fa[top[u]] 这个边不在路径中 是会直接发生 f1 == f2 的 

    所以这样记录是不会出现什么问题的 QAQ

    好久不写 好麻烦...Orz

    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    #include<math.h>
    #include<map>
    #include<iostream>
    #include<string>
    #include<vector>
    #include<queue>
    using namespace std;
    #define L long long
    
    const int maxn = 100050 ;
    
    int top[maxn] , fa[maxn] , deep[maxn] , num[maxn] , p[maxn] , fp[maxn] , son[maxn] ;
    int pos ;
    int n ;
    int a[maxn] ;
    bool can ;
    
    vector<int > q[maxn] ;
    vector<int > w[maxn] ;
    
    vector<int > tmp ;
    
    void init() {
        pos = 1 ;
        memset(son , -1 , sizeof(son)) ;
        for(int i = 1 ; i <= n ; i ++ ) q[i].clear() ;
        for(int i = 1 ; i <= n ; i ++ ) w[i].clear() ;
    }
    
    void dfs1(int u , int pre , int d) {
        deep[u] = d ;
        fa[u] = pre ;
        num[u] = 1 ;
        for(int i = 0 ; i < q[u].size() ; i ++ ){
            int v = q[u][i] ;
            if(v != pre) {
                a[v] = w[u][i] ;
                dfs1(v,u,d+1);
                if(son[u] == -1 || num[v] > num[son[u]]) {
                    son[u] = v ;
                }
            }
        }
    }
    
    void getpos(int u , int sp) {
        top[u] = sp ;
        p[u] = pos ++ ;
        fp[p[u]] = u ;
        if(son[u] == -1) return ;
        getpos(son[u] , sp) ;
        for(int i = 0 ; i < q[u].size() ; i ++ ){
            int v = q[u][i];
            if(v != son[u] && v != fa[u]) {
                getpos(v,v) ;
            }
        }
    }
    
    void slpf(int u ,int v ) {
        int f1 = top[u] , f2 = top[v] ;
        int sl = 0 ;
        while(f1 != f2) {
            if(deep[f1] < deep[f2]) {
                swap(f1 , f2) ;
                swap(u , v) ;
            }
            sl += ( p[u] - p[f1] + 1) ;
            if(sl > 65) {
                can = false ;
                return ;
            }
            else {
                for(int i = p[f1] ; i <= p[u] ; i ++ ){
                    tmp.push_back(a[fp[i]]) ;
                }
            }
            u = fa[f1] ;
            f1 = top[u] ;
        }
        if(u == v) return ;
        if(deep[u] > deep[v]) swap(u , v) ;
        sl += (p[v] - p[son[u]] + 1) ;
        if(sl > 65) {
            can = false ;
            return ;
        }
        for(int i = p[son[u]] ; i <= p[v] ; i ++ ){
            tmp.push_back(a[fp[i]]) ;
        }
    }
    
    int main(){
        while(scanf("%d" , &n) != EOF) {
            init() ;
            for(int i = 1 ; i < n ; i ++ ){
                int u , v , c ;
                scanf("%d%d%d",&u,&v,&c) ;
                q[u].push_back(v) ;
                q[v].push_back(u) ;
                w[u].push_back(c) ;
                w[v].push_back(c) ;
            }
            dfs1(1,0,0) ;
            getpos(1,1) ;
            a[1] = -9999999 ;
            int query ;
            scanf("%d",&query) ;
            for(int i = 1 ; i <= query ; i ++ ){
                int u , v ;
                scanf("%d%d",&u,&v) ;
                tmp.clear() ;
                can = true ;
                slpf(u , v) ;
                if(can == false) {
                    printf("Yes
    ") ;
                }
                else {
                    sort(tmp.begin() , tmp.end()) ;
                    bool ok = false ;
                    if(tmp.size() < 3) {
    
                    }
                    else {
                        for(int j = 2 ; j < tmp.size() ; j ++ ){
                            int aa = tmp[j-2] ;
                            int bb = tmp[j-1] ;
                            int cc = tmp[j] ;
                            if(aa + bb > cc) {
                                ok=true;
                                break ;
                            }
                        }
                    }
                    if(ok)printf("Yes
    ");
                    else printf("No
    ") ;
                }
            }
        }
    }
    

      

  • 相关阅读:
    实际项目管理-1
    arcengine 错误
    一些视频技术类网站
    winform 组件之dotnetbar10.5.3
    winform 弹框的组件
    一个好的开源网站
    写webservice 注意点
    ww
    js
    瀑布流
  • 原文地址:https://www.cnblogs.com/rayrayrainrain/p/6052293.html
Copyright © 2011-2022 走看看