青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

隨筆-80  評論-24  文章-0  trackbacks-0
線段樹是這樣的一棵完全二叉樹,它的每個節點維護著兩個變量start和end,另外還有一些根據特定應用需要維護的值,我們設為x,則它代表著區間[start, end之間的某個特征為x,比如求最值問題,如果有這樣一類問題,比如我們需要給定若干區間[ai, bi],需要查詢這些區間中的最大值(或者最小值),那么線段樹就是最佳選擇,因為它每次的查詢都只需要耗費O(log(bi - ai))時間,效率非常高。線段樹一般采用標準的二叉樹結構實現,維護著left和right指針,以及start和end兩個區間邊界,還有一些和需求有關的域。
下面舉幾個例子,toj的2250題,excellent,題意就是有若干個隊伍,然后進行三次比賽,如果對某支隊伍i,不存在另外一只隊伍j在三次比賽中的排名都比i的排名高,則認為隊伍i是excellent的。輸入是三次比賽的所有排名情況,輸出是excellent隊伍的個數。暴力方法不講了,由于隊伍數量比較多,所以會超時。下面介紹線段樹方法,首先我們知道第一次比賽取得第一名的隊伍a肯定是excellent的,對于第二名隊伍b,我們需要知道隊伍a是否在第二次排名和第三次排名中的名詞都比b高,如果不是,那么b也是excellent,同理,對于第一次比賽中取得第i名的隊伍f[i],我們需要知道是否有一個隊伍f[j] j < i,在第二次比賽和第三次比賽中的名次都比f[i]隊伍高。那么如何才能加速查詢呢?我們可以這樣使用線段樹做:以在第二次比賽中的名次為區間,以第三次比賽的最小名次為特征值。并且初始情況下線段樹為空,每當發現一個excellent隊伍則把它插入到線段樹中,因為仔細想一下不難發現不是excellent的隊伍必定會存在一個已經在線段樹中的隊伍,它的第三次排名比該隊伍小。因此不是excellent的隊伍不需要插入到線段樹中。上面的思想非常巧妙,代碼實現倒是比較簡單,如下:

  1 #include <cstdio>
  2 
  3 #define MAX 0x7fffffff
  4 
  5 //first[i]代表第一次比賽第i名的隊伍編號
  6 int first[100005];
  7 //second_and_third[i].second
  8 //second_and_third[i].third
  9 //上面分別代表第i號隊伍在第二次、第三次比賽中取得的名次
 10 struct st {
 11   int second;
 12   int third;
 13 }second_and_third[100005];
 14 
 15 struct segment_tree {
 16   int min_third;
 17   int start;
 18   int end;
 19   segment_tree *left;
 20   segment_tree *right;
 21 };
 22 
 23 segment_tree *build(int start, int end) {
 24   segment_tree *p = new segment_tree;
 25   p->start = start;
 26   p->end = end;
 27   p->min_third = MAX;
 28   if (start == end) {
 29     p->left = NULL;
 30     p->right = NULL;
 31     return p;
 32   }
 33   p->left = build(start, (start + end) / 2);
 34   p->right = build((start + end) / 2 + 1, end);
 35   return p;
 36 }
 37 
 38 void insert(int second_rank, int third_rank, segment_tree *p) {
 39   if (!p || second_rank < p->start || second_rank > p->end) {
 40     return;
 41   }
 42   if (p->min_third > third_rank) {
 43     p->min_third = third_rank;
 44   }
 45   insert(second_rank, third_rank, p->left);
 46   insert(second_rank, third_rank, p->right);
 47 }
 48 
 49 int check(int start, int end, segment_tree *p) {
 50   if (!p || start > p->end || end < p->start) {
 51     return MAX;
 52   }
 53   if (start <= p->start && end >= p->end) {
 54     return p->min_third;
 55   }
 56   int left = check(start, end, p->left);
 57   int right = check(start, end, p->right);
 58   return left < right ? left : right;
 59 }
 60 
 61 void destroy(segment_tree *p) {
 62   if (!p) {
 63     return;
 64   }
 65   destroy(p->left);
 66   destroy(p->right);
 67   delete p;
 68 }
 69 
 70 int main() {
 71   int n;
 72   while (scanf("%d", &n), n) {
 73     int i, tmp;
 74     for (i = 1; i <= n; ++i) {
 75       scanf("%d", &first[i]);
 76     }
 77     for (i = 1; i <= n; ++i) {
 78       scanf("%d", &tmp);
 79       second_and_third[tmp].second = i;
 80     }
 81     for (i = 1; i <= n; ++i) {
 82       scanf("%d", &tmp);
 83       second_and_third[tmp].third = i;
 84     }
 85     segment_tree *root = build(1, n);
 86     int count = 0;
 87     for (i = 1; i <= n; ++i) {
 88       int second = second_and_third[first[i]].second;
 89       int third = second_and_third[first[i]].third;
 90       int min_third = check(1, second, root);
 91       if (min_third >= third) {
 92         count++;
 93         insert(second, third, root);
 94       }
 95     }
 96     printf("%d\n", count);
 97     delete root;
 98   }
 99   return 0;
100 }

下面看另外一個例題:
此題摘自poj2352(stars),題意:在平面坐標中,有一些stars,每個stars都有整數坐標,且坐標范圍為[0, 32000],stars總數量<=15000。每個星星都屬于一個level,如果滿足{x <=xi && y <= yi}的stars的數量為k個(每個點僅能有一個星星,即星星不能重疊),則我們說(xi, yi)這個star的level為k,現在要輸出每個level擁有星星的數量。該題一個比較特殊的地方是輸入數據已經是按照縱坐標遞增排序了,若縱坐標相等,則按照很坐標遞增排序,所以不需要我們手動排序。現在分析題目:
由于輸入的遞增特性,首先我們可以知道,對每個星星i,滿足{x <=xi && y <= yi}條件的(x, y)的星星必然是在星星i之前輸入的,不會是i輸入之后輸入的星星,因為在y輸入之后的星星y坐標肯定比星星i的y坐標大,或者y坐標相等而x坐標大,這樣都不滿足條件。該題中的y坐標實際上沒有用處,因此這題就變成從第i個輸入a中找出從第1~i - 1的輸入中比a小的數有多少個的問題了。這種問題用線段樹來解時間復雜度非常完美,但是由于線段樹的空間復雜度一直被人詬病,所以這樣做的空間復雜度會有些高。我們的線段樹的每個節點都保存著常規域left和right指針,以及該節點所表示的區間的start和end,最后的特征值我們保存[start, end]區間中的節點數。這樣,當第i個節點a來到時,我們需要向線段樹中插入,插入函數返回值即當前已經輸入的星星中x坐標小于a的個數。這里是代碼的核心,如果a < start那么我們可以直接返回0了;否則如果a > end,則我們可以直接返回當前節點的[start, end]中所有的節點個數了,因為在[start, end]的區間中的所有節點的x坐標必定都小于a,因為a > end(這不廢話嘛……);否則若a == start && a == end,則說明當前節點已經為葉子節點了,那么直接返回當前節點的星星數量,然后再將a插入到該節點,即當前節點的星星數量加1;最后的情況肯定就是a在區間[start, end]之間了,這時候遞歸向左子樹和右子樹插入即可,返回值相加即是[start, end]中小于a的星星的數量。說的比較羅嗦,看代碼吧:

 1 #include <cstdio>
 2 #include <cstdlib>
 3 
 4 #define MAX 15005
 5 
 6 int stars_x[MAX];
 7 int levels[MAX];
 8 
 9 struct segment_tree {
10   int start;
11   int end;
12   int node_num;
13   segment_tree *left;
14   segment_tree *right;
15 };
16 
17 segment_tree *create_segment_tree(int start, int end) {
18   segment_tree *p = (segment_tree *)malloc(sizeof(segment_tree));
19   p->start = start;
20   p->end = end;
21   p->node_num = 0;
22   if (start == end) {
23     p->left = p->right = NULL;
24   } else {
25     p->left = create_segment_tree(start, (end + start) / 2);
26     p->right = create_segment_tree((end + start) / 2 + 1, end);
27   }
28   return p;
29 }
30 
31 int insert_into_segment_tree(int x, segment_tree *t) {
32   if (!t || x < t->start) {
33     return 0;
34   }
35   if (x > t->end) {
36     return t->node_num;
37   }
38   if (x == t->start && x == t->end) {
39     return t->node_num++;
40   }
41   t->node_num++;
42   int left_num = insert_into_segment_tree(x, t->left);
43   int right_num = insert_into_segment_tree(x, t->right);
44   return left_num + right_num;
45 }
46 void release(segment_tree *p) {
47   if (!p) {
48     return;
49   }
50   release(p->left);
51   release(p->right);
52   free(p);
53 }
54 
55 int main() {
56   int n;
57   scanf("%d", &n);
58   int i, max_x = -1, tmpy;
59   for (i = 0; i < n; ++i) {
60     scanf("%d%d", &stars_x[i], &tmpy);
61     if (max_x < stars_x[i]) {
62       max_x = stars_x[i];
63     }
64     levels[i] = 0;
65   }
66 
67   segment_tree *root = create_segment_tree(0, max_x + 2);
68 
69   for (i = 0; i < n; ++i) {
70     int num = insert_into_segment_tree(stars_x[i], root);
71     levels[num]++;
72   }
73 
74   for (i = 0; i < n; ++i) {
75     printf("%d\n", levels[i]);
76   }
77 
78   release(root);
79   return 0;
80 }

注意如果直接拿這個代碼提交會TLE,主要時間其實耗費在了建線段樹上了, 因為我們采用的是用malloc從堆中分配,沒開辟一個節點就調用一次malloc函數,非常耗費時間,我第一次提交就TLE了,不過可以不需要把其改成用數組表示線段樹的形式,可以直接不管內存釋放,直接把release(root)語句刪除,然后把release()函數刪除,這樣提交的代碼恰好1000ms,太驚險了。如果用數組表示線段樹的話相信時間會快很多,這就是oj的特點。另外需要說明的是把malloc替換成new的話會超過1000ms,超時,說明還是用malloc效率高一些。
posted on 2012-09-13 14:31 myjfm 閱讀(1281) 評論(0)  編輯 收藏 引用 所屬分類: 算法基礎
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            国产精品高清免费在线观看| 一区二区成人精品| 亚洲美女色禁图| 亚洲国产精品久久久久婷婷884| 国产日韩一区二区三区在线| 国内精品亚洲| 亚洲黄网站黄| 亚洲午夜激情网页| 欧美一区二区三区喷汁尤物| 午夜宅男久久久| 久久久噜噜噜久久久| 免费国产自线拍一欧美视频| 亚洲国产精品久久久久久女王 | 久久久久九九九| 蜜臀久久99精品久久久画质超高清| 欧美激情亚洲国产| 中文精品在线| 美女爽到呻吟久久久久| 国产精品jvid在线观看蜜臀| 激情综合视频| 亚洲视频在线看| 免费成人网www| 999在线观看精品免费不卡网站| 性欧美暴力猛交69hd| 激情欧美日韩| 一本大道av伊人久久综合| 午夜精品久久久久久久蜜桃app| 麻豆精品视频在线观看| 一本色道久久加勒比88综合| 久久久青草婷婷精品综合日韩| 欧美视频在线视频| 亚洲高清不卡一区| 久久久亚洲精品一区二区三区 | 一本色道精品久久一区二区三区| 午夜亚洲精品| 欧美色图天堂网| 亚洲国产欧美一区二区三区久久| 午夜精品美女自拍福到在线| 亚洲青色在线| 久久精品欧美| 国产精品免费视频xxxx | 男人的天堂亚洲| 亚洲欧美激情四射在线日| 欧美精品v日韩精品v国产精品| 国产一区二区按摩在线观看| 亚洲第一页中文字幕| 美日韩精品免费观看视频| 久久亚洲精品伦理| 男女激情久久| 亚洲国产精品久久久久秋霞蜜臀 | 亚洲欧美精品| 欧美激情女人20p| 99国产精品久久久久老师| 99re在线精品| 欧美激情在线播放| 亚洲精品视频免费观看| 你懂的亚洲视频| 久久久噜噜噜久久中文字幕色伊伊| 国产精品网站在线| 亚洲小说区图片区| 亚洲视频播放| 国产精品久久网站| 亚洲欧美色一区| 午夜精品久久| 国产视频精品xxxx| 久久综合久久综合九色| 久久福利影视| 亚洲高清在线观看| 亚洲国产精品国自产拍av秋霞| 玖玖玖国产精品| 亚洲一区亚洲二区| 国产精品久久亚洲7777| 亚洲一区二区三区精品视频 | 欧美一区1区三区3区公司| 国产精品乱子乱xxxx| 午夜精品区一区二区三| 午夜免费久久久久| 国内精品嫩模av私拍在线观看| 免费高清在线一区| 欧美成人午夜影院| 亚洲国产精品一区制服丝袜| 亚洲精品日韩在线| 欧美丝袜一区二区| 久久www成人_看片免费不卡| 欧美在线观看视频在线| 日韩视频第一页| 国产精品乱人伦一区二区| 久久综合五月| 欧美激情va永久在线播放| 亚洲伊人网站| 久久精品在线免费观看| 洋洋av久久久久久久一区| 亚洲在线视频一区| 在线欧美不卡| 亚洲影视九九影院在线观看| 依依成人综合视频| 一本色道久久88综合亚洲精品ⅰ| 黑人极品videos精品欧美裸| 亚洲精品久久视频| 国产一区日韩欧美| 99re成人精品视频| 玉米视频成人免费看| 中文av字幕一区| 亚洲二区在线观看| 亚洲欧美影院| 99日韩精品| 久久久久久91香蕉国产| 性欧美大战久久久久久久久| 欧美成人资源| 久久先锋影音av| 国产精品久久久| 亚洲丰满在线| 激情五月***国产精品| 亚洲尤物精选| 宅男精品视频| 欧美福利视频在线| 蜜乳av另类精品一区二区| 国产精品免费看久久久香蕉| 亚洲精品美女免费| 亚洲大胆美女视频| 欧美一级专区| 欧美呦呦网站| 欧美日韩国产影片| 欧美国产一区二区在线观看| 狠狠色狠狠色综合日日五| 亚洲欧美日韩精品久久久久| 亚洲香蕉成视频在线观看| 欧美激情一区二区三区蜜桃视频 | 麻豆成人综合网| 蜜桃伊人久久| 国产亚洲一区二区三区在线播放| 亚洲免费在线视频| 午夜精品美女久久久久av福利| 国产精品高清免费在线观看| 日韩视频一区二区| 一二三四社区欧美黄| 欧美啪啪成人vr| 日韩视频永久免费| 一区二区三区四区精品| 欧美日韩国产在线一区| 老司机午夜精品| 欧美一级理论性理论a| 国产精品大片wwwwww| 9l视频自拍蝌蚪9l视频成人| 日韩午夜一区| 欧美视频中文字幕| 亚洲伊人久久综合| 欧美在线一级va免费观看| 国内免费精品永久在线视频| 欧美一区免费| 欧美高清视频www夜色资源网| 亚洲精品免费看| 欧美日韩免费观看一区| 99精品视频一区二区三区| 亚洲一级免费视频| 国产精品亚洲一区| 久久大逼视频| 欧美国产日韩免费| 亚洲深夜福利在线| 国产精品av免费在线观看 | 麻豆久久精品| 亚洲精品日产精品乱码不卡| 欧美日韩性视频在线| 亚洲一二三区精品| 久久全球大尺度高清视频| 亚洲高清在线观看| 欧美日韩一区二区在线| 亚洲一级黄色av| 免费观看成人鲁鲁鲁鲁鲁视频| 亚洲日韩第九十九页| 欧美日韩国产黄| 亚洲欧美成人一区二区在线电影| 久久久久国产一区二区三区| 99视频一区| 国产婷婷色一区二区三区在线 | 欧美午夜三级| 久久www免费人成看片高清| 亚洲人成在线影院| 久久精品国产一区二区电影| 亚洲国产一区二区精品专区| 欧美亚州在线观看| 蜜桃久久精品乱码一区二区| 亚洲性视频h| 亚洲国产精品国自产拍av秋霞| 久久激五月天综合精品| 亚洲伦理网站| 在线成人小视频| 国产精品综合不卡av | 1024欧美极品| 国产精品你懂得| 欧美国产一区二区三区激情无套| 午夜视频一区在线观看| 日韩亚洲国产精品| 欧美韩日高清| 美日韩丰满少妇在线观看| 先锋影音一区二区三区| 亚洲视频在线一区观看| 亚洲国产欧美日韩精品| 在线观看不卡| 好看不卡的中文字幕|