8月8号的线段树:HDU 1754&&POJ 3264&&HDU1166

很明显,没有A一道题,题目意思很容易懂,但是就是shit的超时!!

之后就崩溃了。

晚上好像弄懂了线段树,先上题目:

                                              I Hate It HDU 1754

要用线段树才不会超时:

(计算机运行数目达到10^8就要1S了!!而一般题目就是那么2000MS~5000MS)

 

 1 #include<iostream>
 2 #include<stdio.h>
 3 #include<algorithm>
 4 using namespace std;
 5 int a[200005];
 6 struct line
 7 {
 8     int left;
 9     int right;
10     int max1;
11 }node[200005*20];
12 void build(int left,int right,int root)
13 {
14     node[root].left=left;
15     node[root].right=right;
16     if(left==right)
17     {
18         node[root].max1=a[left];
19     }
20     else
21     {
22         build(left,(left+right)/2,2*root);
23         build((left+right)/2+1,right,2*root+1);
24         node[root].max1=max(node[2*root].max1,node[2*root+1].max1);
25     }
26 }
27 int find1(int left1,int right1,int root)
28 {
29     if(node[root].left>right1||node[root].right<left1)
30         return 0;
31     if(left1<=node[root].left&&right1>=node[root].right)
32         return node[root].max1;
33     int a,b;
34     a=find1(left1,right1,2*root);
35     b=find1(left1,right1,2*root+1);
36     return max(a,b);
37 }
38 int update(int x,int y,int root)
39 {
40     if(x<node[root].left||x>node[root].right)
41         return 0;
42     if(node[root].left==x&&node[root].right==x)
43     return node[root].max1=y;
44     node[root].max1=max(update(x,y,2*root),update(x,y,2*root+1));
45     return node[root].max1;
46 }//这里不仅把自己的值更新,而且把改变之后每个根节点的最大值也进行了更新!
47 int main()
48 {
49     int i,n,m,a1,a2;
50     char b[2];
51     while(scanf("%d%d",&n,&m)!=EOF)
52     {
53         for(i=1;i<=n;i++)
54             scanf("%d",&a[i]);
55         build(1,n,1);
56         while(m--)
57         {
58             scanf("%s%d%d",b,&a1,&a2);
59             if(b[0]=='Q')
60                 printf("%d\n",find1(a1,a2,1));
61             else
62             {
63                 a[a1]=a2;
64                 update(a1,a2,1);
65             }
66         }
67     }
68     return 0;
69 }

 

 

 

第一次看懂:首先题目数据的默认顺序应该是1,2,3,4...(不然那个线段树怎么判断找哪个点到哪个点)

还有根节点,左节点,右节点的求法确定(即树的大体样子要清楚)

找东西的话(题目从线段数要求解的),得从根节点往下找起!

以根节点为依据,看他们的左右孩子和问题的关系。(包围还是半包围)

                                     Balanced Lineup  POJ 3264

上面一个题的变行:这里不要update.

 1 #include<iostream>
 2 #include<stdio.h>
 3 #include<algorithm>
 4 using namespace std;
 5 int a[50005];
 6 int MaxNum,MinNum;
 7 struct line
 8 {
 9     int left;
10     int right;
11     int max1;
12     int min1;
13 }node[50005*20];
14 void build(int left,int right,int root)
15 {
16     node[root].left=left;
17     node[root].right=right;
18     if(left==right)
19     {
20         node[root].max1=a[left];
21         node[root].min1=a[right];
22     }
23     else
24     {
25         build(left,(left+right)/2,root*2);
26         build((left+right)/2+1,right,2*root+1);
27         node[root].max1=max(node[root*2].max1,node[root*2+1].max1);
28         node[root].min1=min(node[root*2].min1,node[root*2+1].min1);
29     }
30 }
31 int find1(int left1,int right1,int root)
32 {
33     if(left1>node[root].right||right1<node[root].left)
34         return 0;
35     if(left1<=node[root].left&&right1>=node[root].right)
36     {
37             MaxNum=max(node[root].max1,MaxNum);
38             MinNum=min(node[root].min1,MinNum);
39             return (MaxNum-MinNum);
40     }
41     int a,b;
42     a=find1(left1,right1,2*root);
43     b=find1(left1,right1,2*root+1);
44     return max(a,b);
45 }
46 int main()
47 {
48     int n,m,i,a1,a2;
49     while(scanf("%d%d",&n,&m)!=EOF)
50     {
51         for(i=1;i<=n;i++)
52             scanf("%d",&a[i]);
53         build(1,n,1);
54         while(m--)
55         {
56             scanf("%d%d",&a1,&a2);
57             MaxNum = -99999999;
58             MinNum = 99999999;
59             printf("%d\n",find1(a1,a2,1));
60         }
61     }
62     return 0;
63 }

 为什么上面的第一题不用开个MaxNum来求最大值,而后面的题目要开个MaxNum,MinNum来求最大值和最小值?

那是因为第一题只要求最大值,而第二题那最大值和最小值可能不在同一if判断语句中啊!!!!!

(貌似这个问题只有我才会犯的吧,主要是第二题的代码直接是第一题的克隆体,才会那么在意那些不同之处!)

 

                              敌兵布阵 HDU1166

加深对线段树的理解:(首先明确一旦建立好线段树,那么就不会有重叠和交叉)

 1 #include<iostream>
 2 #include<stdio.h>
 3 #include<algorithm>
 4 using namespace std;
 5 int a[50005],ans;
 6 struct line
 7 {
 8     int left;
 9     int right;
10     int sum;
11 }node[50005*20];
12 void build(int left,int right,int root)
13 {
14     node[root].left=left;
15     node[root].right=right;
16     if(left==right)
17         node[root].sum=a[left];
18     else
19     {
20         build(left,(left+right)/2,2*root);
21         build((left+right)/2+1,right,2*root+1);
22         node[root].sum=node[root*2].sum+node[root*2+1].sum;
23     }
24 }
25 void query(int left1,int right1,int root)
26 {
27     if(left1>node[root].right||right1<node[root].left)
28         return ;
29     if(left1<=node[root].left&&right1>=node[root].right)
30          ans+=node[root].sum;
31     else
32     {
33         query(left1,right1,2*root);
34         query(left1,right1,2*root+1);
35     }
36 }
37 void insert1(int x,int y,int root)
38 {
39     if(x<node[root].left||x>node[root].right)
40         return ;
41     if(x>=node[root].left&&x<=node[root].right)
42          node[root].sum+=y;
43     insert1(x,y,2*root);
44     insert1(x,y,2*root+1);
45 }
46 int main()
47 {
48     int d=0,t,n,i,a1,a2;
49     char b[8];
50     scanf("%d",&t);
51     while(t--)
52     {
53         scanf("%d",&n);
54         for(i=1;i<=n;i++)
55             scanf("%d",&a[i]);
56         build(1,n,1);
57         printf("Case %d:\n",++d);
58         while(scanf("%s",b)!=EOF)
59         {
60             if(b[0]=='E')
61                 break;
62             scanf("%d%d",&a1,&a2);
63             if(b[0]=='Q')
64             {
65                 ans=0;
66                 query(a1,a2,1);
67                 printf("%d\n",ans);
68             }
69             else if(b[0]=='A')
70                 insert1(a1,a2,1);
71             else
72                 insert1(a1,-a2,1);
73       }
74     }
75     return 0;
76 }

 

 

posted on 2013-08-08 22:00  ~~碾压机  阅读(178)  评论(0编辑  收藏  举报