poj线段树

解题报告

做了两个poj线段树的题目,感觉不错。 线段树是一个进行区间操作的好工具!我们正常使用的大多是二叉树,也就是将一个区间二分分解,将我们想要记录的区间的信息放入二叉树节点中去,然后进行查找和修改都是logn的时间,由于是二分分解的,于是他是一颗标准的类堆状树,即,他的深度很低,很饱满,效率很好。

因为线段树是进行区间操作的,因此看到和区间有关系的问题时,先想一想一块区间的某些信息能否与题目要解决的问题合在一起。这里是使用线段是最难的地方吧。一定想清楚了。

 

//poj3321 很普通的区间求和的题目,但是先得将题目中的多叉树先根或后根遍历,得到序列,并记录节点在树中位置,和节点儿子的个数(化为序列后,u的儿子个数就是从u开始求和的区间范围)。

#include <cstdio>

#include <cstring>

 

#define MAXN 100100

#define root 1

 

struct Segment_Tree{

         int son_l, son_r;

         int led, red;

         int sum;

         int flag;

};

 

Segment_Tree S_T[MAXN * 10];

 

struct EDGE{

         int to, next;

} edges[MAXN * 2];

int head[MAXN], ad, son[MAXN], site[MAXN], vis[MAXN];

int n, Time, ANS;

 

void clear(){

         memset(head, -1, sizeof(head));

         ad = 0;

}

 

void insert(int u, int v){

         edges[ad].to = v; edges[ad].next = head[u]; head[u] = ad ++;

}

 

void dfs(int u){

         vis[u] = 1;

         site[u] = ++ Time;

         son[u] = 0;

         for(int p = head[u]; ~p; p = edges[p].next){

                   int v = edges[p].to;

                   if(!vis[v]){

                            dfs(v);

                            son[u] += son[v] + 1;

                   }

         }

}

 

void Built_Segment_Tree(int rt, int l, int r){

         S_T[rt].led = l;

         S_T[rt].red = r;

         S_T[rt].flag = 1;

         if(l == r) S_T[rt].sum = 1;

         else S_T[rt].sum = 0;

         if(l != r){

                   Built_Segment_Tree((S_T[rt].son_l = rt * 2), l, (l + r) / 2);

                   S_T[rt].sum += S_T[S_T[rt].son_l].sum;

                   Built_Segment_Tree((S_T[rt].son_r = rt * 2 + 1), (l + r) / 2 + 1, r);

                   S_T[rt].sum += S_T[S_T[rt].son_r].sum;

         }

         else S_T[rt].son_l = S_T[rt].son_r = -1;

}

 

void Change(int l, int r, int x, int rt){

         if(l == r && l == x){

                   if(S_T[rt].flag){

                            S_T[rt].flag = 0;

                            S_T[rt].sum -= 1;

                   }

                   else{

                            S_T[rt].flag = 1;

                            S_T[rt].sum += 1;

                   }

         }

         else{

                   int mid = (l + r) / 2;

                   if(x > mid){

                            Change(mid + 1, r, x, S_T[rt].son_r);

                            if(S_T[S_T[rt].son_r].flag){

                                     S_T[rt].flag = 1;

                                     S_T[rt].sum += 1;

                            }

                            else{

                                     S_T[rt].flag = 0;

                                     S_T[rt].sum -= 1;

                            }

                   }

                   else{

                            Change(l, mid, x, S_T[rt].son_l);

                            if(S_T[S_T[rt].son_l].flag){

                                     S_T[rt].flag = 1;

                                     S_T[rt].sum += 1;

                            }

                            else{

                                     S_T[rt].flag = 0;

                                     S_T[rt].sum -= 1;

                            }

                   }

         }

}

 

void answer(int rt, int pl, int pr){

         if(S_T[rt].led >= pl && S_T[rt].red <= pr){ ANS += S_T[rt].sum; return;}

         if(S_T[rt].led > pr || S_T[rt].red < pl) return;

         answer(S_T[rt].son_l, pl, pr);

         answer(S_T[rt].son_r, pl, pr);

}

 

int main(){

         int n, i, x, y, m;

         char ch[2];

         while(~scanf("%d", &n)){

                   clear();

                   for(i = 1; i < n; ++ i){

                            scanf("%d %d", &x, &y);

                            insert(x, y);

                            insert(y, x);

                   }

                   memset(vis, 0, sizeof(vis));

                   Time = 0;

                   dfs(root);

                   Built_Segment_Tree(root, 1, n);

                   scanf("%d", &m);

                   while(m --){

                            scanf("%s %d", ch, &x);

                            switch(ch[0]){

                            case 'Q' : ANS = 0;

                                                  answer(root, site[x], site[x] + son[x]);

                                                  printf("%d\n", ANS);

                                                  break;

                            case 'C' : Change(1, n, site[x], root);

                                                  break;

                            }

                   }

         }

         return 0;

}

 

 

 

 

//poj2528 区间染色问题。我们的区间记录的信息是这段区间内每个点的颜色,也就是说只有区间内颜色有一样的区间才是我们要用的有价值的。要注意的是:假设之前有一区间[2,5]颜色都是1,现在将[3,5]的颜色染成2,那么我们依然需要再次将[2,2]的颜色染成1,因为这个操作破坏了[2,5]区间的特征,[2,5]已经不能代表它里面的所有点的信息,我们需要给每个点再找一个“区间代表”。

#include <cstdio>

#include <map>

#include <algorithm>

using namespace std;

 

#define MAXN (10100 * 2)

#define root 1

 

struct Segment_Tree_node{

    int led, red;

    int son_l, son_r;

    int flag;

    int colour;

}S_T[MAXN * 10];

 

struct Comp{

    bool operator()(constint &A, const int &B)const{

       return A > B;

    }

};

 

map<int,int, Comp> M;

 

struct LINE_node{

    int l, r;

} edges[MAXN];

int num[MAXN], n;

 

void Disperse(int m){

    sort(num, num + m);

    M[num[0]] = 1;

    for(int i = 1, t = 1;i < m; ++ i)

       if(num[i]!= num[i - 1]){

           if(num[i] - num[i - 1] > 1)

              M[num[i]] = M[num[i- 1]] + 2;

           else

              M[num[i]] = M[num[i- 1]] + 1;

       }

    for(int i = 0; i <n; i ++){

       edges[i].l = M[edges[i].l];

       edges[i].r = M[edges[i].r];

    }

}

 

void Bulit_Segment_Tree(int rt, int l, intr){

    S_T[rt].led = l;

    S_T[rt].red = r;

    S_T[rt].flag = 0;

    if(l !=r){

       Bulit_Segment_Tree(S_T[rt].son_l =rt * 2, l, (l + r) / 2);

       Bulit_Segment_Tree(S_T[rt].son_r =rt * 2 + 1, (l + r) /2 + 1, r);

    }

    else  S_T[rt].son_l =S_T[rt].son_r = -1;

}

 

void Change(int rt, int pl, intpr, int col){

    if(pr <pl) return;

    if(S_T[rt].led>= pl && S_T[rt].red <= pr){

       S_T[rt].colour = col;

       S_T[rt].flag = 1;

       return;

    }

    if(S_T[rt].led> pr || S_T[rt].red < pl) return;

    if(S_T[rt].led<= pl && S_T[rt].red >= pr){

       if(S_T[rt].flag){

           S_T[rt].flag = 0;

           Change(S_T[rt].son_l, pl,pr, col);

           Change(S_T[rt].son_r, pl,pr, col);

           Change(rt, S_T[rt].led,pl - 1, S_T[rt].colour);

           Change(rt, pr +1, S_T[rt].red, S_T[rt].colour);

       }

       else{

           Change(S_T[rt].son_l, pl,pr, col);

           Change(S_T[rt].son_r, pl,pr, col);

       }

    }

    else{

       if(S_T[rt].led>= pl){

           if(S_T[rt].flag){

              S_T[rt].flag = 0;

              Change(S_T[rt].son_l, pl,pr, col);

              Change(S_T[rt].son_r, pl,pr, col);

              Change(rt, pr +1, S_T[rt].red, S_T[rt].colour);

           }

           else{

              Change(S_T[rt].son_l, pl,pr, col);

              Change(S_T[rt].son_r, pl,pr, col);

           }

       }

       else{

           if(S_T[rt].flag){

              S_T[rt].flag = 0;

              Change(S_T[rt].son_l, pl,pr, col);

              Change(S_T[rt].son_r, pl,pr, col);

              Change(rt, S_T[rt].led,pl - 1, S_T[rt].colour);

           }

           else{

              Change(S_T[rt].son_l, pl,pr, col);

              Change(S_T[rt].son_r, pl,pr, col);

           }

       }

    }

}

 

int Get_colour(int rt, int x){

    if(S_T[rt].led== S_T[rt].red)return S_T[rt].flag? S_T[rt].colour : -1;

    if(S_T[rt].flag)return S_T[rt].colour;

    if(x >(S_T[rt].led + S_T[rt].red) / 2) return Get_colour(S_T[rt].son_r, x);

    else Get_colour(S_T[rt].son_l, x);

}

 

int main(){

    int i, CASE, m, col;

    scanf("%d",&CASE);

    while(CASE--){

       scanf("%d",&n);

       m = 0;

       for(i =0; i < n; ++ i){

           scanf("%d %d", &edges[i].l, &edges[i].r);

           num[m ++] = edges[i].l;

           num[m ++] = edges[i].r;

       }

       Disperse(m);

       m = M[num[m- 1]];

       Bulit_Segment_Tree(root, 1, m);

       for(i =0; i < n; ++ i)

           Change(root, edges[i].l,edges[i].r, i + 1);

       memset(num, 0, sizeof(num));

       int ans = 0;

       for(i =1; i <= m; i ++){

           col = Get_colour(root,i);

           if(col == -1) continue;

           if(!num[col]){

              num[col] = 1;

              ans ++;

           }

       }

       printf("%d\n",ans);

    }

    return 0;

}

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值