您的位置:首页 > 其它

poj线段树

2013-11-18 16:02 225 查看
解题报告

做了两个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;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: