线段树基础

题集:http://blog.csdn.net/qq574857122/article/details/11727859

单点更新:

HDU 1166 单点改值+区间求和;

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 using namespace std;
 5 
 6 #define LL(x) (x<<1)
 7 #define RR(x) (x<<1|1)
 8 #define MID(a,b) (a+((b-a)>>1))
 9 const int N=50005;
10 
11 struct node
12 {
13     int lft,rht;
14     int sum;
15     int mid()
16     {
17         return MID(lft,rht);
18     }
19 };
20 
21 int y[N],n;
22 
23 struct Segtree
24 {
25     node tree[N*4];
26     void build(int lft,int rht,int ind)
27     {
28         tree[ind].lft=lft;
29         tree[ind].rht=rht;
30         tree[ind].sum=0;
31         if(lft==rht) tree[ind].sum=y[lft];
32         else
33         {
34             int mid=tree[ind].mid();
35             build(lft,mid,LL(ind));
36             build(mid+1,rht,RR(ind));
37             tree[ind].sum=tree[LL(ind)].sum+tree[RR(ind)].sum;
38         }
39     }
40     void updata(int pos,int ind,int valu)
41     {
42         if(tree[ind].lft==tree[ind].rht) tree[ind].sum+=valu;
43         else
44         {
45             int mid=tree[ind].mid();
46             if(pos<=mid) updata(pos,LL(ind),valu);
47             else updata(pos,RR(ind),valu);
48             tree[ind].sum=tree[LL(ind)].sum+tree[RR(ind)].sum;
49         }
50     }
51     int query(int st,int ed,int ind)
52     {
53         int lft=tree[ind].lft,rht=tree[ind].rht;
54         if(st<=lft&&rht<=ed) return tree[ind].sum;
55         else
56         {
57             int mid=tree[ind].mid();
58             int sum1=0,sum2=0;
59             if(st<=mid) sum1=query(st,ed,LL(ind));
60             if(ed>mid) sum2=query(st,ed,RR(ind));
61             return sum1+sum2;
62         }
63     }
64 } seg;
65 int main()
66 {
67     int t,t_cnt=0;
68     scanf("%d",&t);
69     while(t--)
70     {
71         int a,b;
72         char str[10];
73         scanf("%d",&n);
74         for(int i=1; i<=n; i++) scanf("%d",&y[i]);
75         seg.build(1,n,1);
76 
77         printf("Case %d:\n",++t_cnt);
78         while(1)
79         {
80             scanf("%s",str);
81             if(strcmp(str,"End")==0) break;
82             scanf("%d%d",&a,&b);
83             if(strcmp(str,"Add")==0) seg.updata(a,1,b);
84             else if(strcmp(str,"Sub")==0) seg.updata(a,1,-b);
85             else printf("%d\n",seg.query(a,b,1));
86         }
87     }
88     return 0;
89 }
View Code

HDU1574 单点改值+区间求最值:

  1 #include <iostream>
  2 #include <algorithm>
  3 #include <cstdio>
  4 #include <cstdlib>
  5 #include <cstring>
  6 using namespace std;
  7 #define LL(x) (x<<1)
  8 #define RR(x) (x<<1|1)
  9 #define MID(a,b) (a+((b-a)>>1))
 10 const int N=200010;
 11 struct node
 12 {
 13     int lft,rht;
 14     int sum,maxn;
 15     int mid()
 16     {
 17         return MID(lft,rht);
 18     }
 19 };
 20 int y[N],n;
 21 
 22 struct Segtree
 23 {
 24     node tree[N*4];
 25     void build(int lft,int rht,int ind)
 26     {
 27         tree[ind].lft=lft;
 28         tree[ind].rht=rht;
 29         tree[ind].sum = 0;
 30         tree[ind].maxn = 0;
 31         if(lft == rht) tree[ind].sum=y[lft],tree[ind].maxn = y[lft];
 32         else
 33         {
 34             int mid=tree[ind].mid();
 35             build(lft,mid,LL(ind));
 36             build(mid+1,rht,RR(ind));
 37             tree[ind].sum=tree[LL(ind)].sum+tree[RR(ind)].sum;
 38             tree[ind].maxn=max(tree[ind].maxn,max(tree[LL(ind)].maxn,tree[RR(ind)].maxn));
 39         }
 40     }
 41     void updata(int pos,int ind,int valu)
 42     {
 43         if(tree[ind].lft==tree[ind].rht)
 44         {
 45             tree[ind].maxn = valu;///直接改值
 46             ///tree[ind].maxn += valu;///加上某值
 47         }
 48 
 49         else
 50         {
 51             int mid=tree[ind].mid();
 52             if(pos <= mid) updata(pos,LL(ind),valu);
 53             else updata(pos,RR(ind),valu);
 54             tree[ind].sum=tree[LL(ind)].sum+tree[RR(ind)].sum;
 55             tree[ind].maxn=max(tree[ind].maxn,max(tree[LL(ind)].maxn,tree[RR(ind)].maxn));
 56         }
 57     }
 58     int query(int st,int ed,int ind)
 59     {
 60         int lft = tree[ind].lft,rht=tree[ind].rht;
 61         if(st<=lft&&rht<=ed)
 62         {
 63             return tree[ind].maxn;
 64             ///return tree[ind].sum;///就是区间求和
 65         }
 66         else
 67         {
 68             int mid=tree[ind].mid();
 69             int sum1=0,sum2=0;
 70             if(st <= mid)
 71                 sum1=max(sum1,query(st,ed,LL(ind)));
 72             if(ed > mid)
 73                 sum2=max(sum2,query(st,ed,RR(ind)));
 74             return max(sum1,sum2);
 75             ///返回区间和
 76 ///            if(st<=mid) sum1=query(st,ed,LL(ind));
 77 ///            if(ed>mid) sum2=query(st,ed,RR(ind));
 78 ///            return sum1+sum2;
 79         }
 80     }
 81 } seg;
 82 int main()
 83 {
 84     int t,t_cnt=0,m;
 85     while(~scanf("%d%d",&n,&m))
 86     {
 87         int a,b;
 88         char str[10];
 89         for(int i=1; i<=n; i++)
 90             scanf("%d",&y[i]);
 91         seg.build(1,n,1);
 92         while(m--)
 93         {
 94             scanf("%s",str);
 95             scanf("%d%d",&a,&b);
 96             if(strcmp(str,"U")==0)///单点改值
 97                 seg.updata(a,1,b);
 98             else
 99                 printf("%d\n",seg.query(a,b,1));///求最大值
100         }
101     }
102     return 0;
103 }
修改上面的模板即可

HDU 1394 给一个序列,依次把最后一个数移到第一个数的位置上,求n个序列最小逆序数。

求初始逆序对数nlogn , 其他逆序对数O(1),也可以用树状数组,对数列的要求不高,不必非得连续也能求(离散化)

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 #define clr(a, x) memset(a, x, sizeof a)
 6 #define repu(i, a, b) for(int i = a; i < b; i++)
 7 #define ls (rt<<1)
 8 #define rs (ls|1)
 9 #define lson l, mid, ls
10 #define rson mid+1, r, rs
11 #define INF 0x3f3f3f3f
12 using namespace std;
13 const int maxn=100050;
14 struct SegmentTree
15 {
16     int sum[maxn<<2];
17     void pushup(int rt)
18     {
19         sum[rt]=sum[ls]+sum[rs];
20     }
21     void build(int l,int r,int rt)
22     {
23         sum[rt]= 0;
24         if(l == r)
25             return ;
26         int mid = (l+r)>>1;
27         build(lson);
28         build(rson);
29     }
30     void update(int p, int l, int r, int rt)
31     {
32         if(l==r)
33         {
34             cout<<rt<<endl;
35             sum[rt]++;///逆序数
36             ///sum[rt] += add;///区间求和,add是参数传进来
37             ///Max[rt] = add;///区间最值
38             return ;
39         }
40         int mid=l+r>>1;
41         if(p <= mid) update(p, lson);
42         if(p > mid) update(p, rson);
43         pushup(rt);
44     }
45     int query(int L, int R, int l, int r, int rt)
46     {
47         if(L <= l && R >= r)
48             return sum[rt];
49         int mid = l + r >> 1;
50         int ans=0;
51         if(L <= mid)
52             ans += query(L, R, lson);
53         if(R > mid)
54             ans += query(L, R, rson);
55         return ans;
56     }
57 } st;
58 int main()
59 {
60     int n, m, a[maxn];
61     while(~scanf("%d", &n))
62     {
63         st.build(0,n-1,1);
64         int tot = 0;
65         repu(i,0,n)
66         {
67             scanf("%d",&a[i]);
68             tot += st.query(a[i],n-1,0,n-1,1);///a[i]做左区间
69             st.update(a[i],0,n-1,1);///在a[i]这个位置上更新sum
70         }
71         ///tot就是初始序列的逆序对数
72         int minn = INF;
73         ///1 3 6 9 0 8 5 7 4 2
74         ///2 1 3 6 9 0 8 5 7 4
75         ///2后面每一个比2大的数字都应该-1
76         ///2在第一个位置上,后面肯定有0,1是逆序对
77         ///因此公式就是tot - (n - 2 - 1) + 2;
78         for(int i = n-1; i>0; i--)///倒着来,才能用下面的公式
79         {
80             tot = tot - (n - a[i] - 1) + a[i];
81             minn = min(minn,tot);
82         }
83         printf("%d\n",minn);
84     }
85     return 0;
86 }
求初始逆序数用到线段树,只解决排序后是连续的数列

HDU 2759(维护区间最大位置信息)

题目大意:有一块h*w的矩形广告板,要往上面贴广告,然后给n个1*wi的广告,要求把广告贴上去,而且要求广告要尽量往上贴并且尽量靠左,求第n个广告的所在的位置,不能贴则为-1;

hh代码--还没理解透

区间更新

HDU 1698:区间[a,b]里的数更新为c,问最后这N个数的和是多少;

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 using namespace std;
  5 #define LL(x) (x<<1)
  6 #define RR(x) (x<<1|1)
  7 #define MID(a,b) (a+((b-a)>>1))
  8 const int N=100005;
  9 struct node
 10 {
 11     int left,right;
 12     int sum,type;
 13     int mid()
 14     {
 15         return MID(left,right);
 16     }
 17     void fun(int tmp)///这个函数是干嘛的。。。
 18     {
 19         type = tmp;
 20         sum =(right-left+1)*type;
 21     }
 22 ///    void fun(int tmp)///对区间内的数做加操作
 23 ///    {
 24 ///        type += tmp;
 25 ///        sum  +=(right-left+1)*type;
 26 ///    }
 27 };
 28 struct Segtree
 29 {
 30     node tree[N*4];
 31     void build(int left,int right,int ind)
 32     {
 33         tree[ind].left=left;
 34         tree[ind].right=right;
 35         tree[ind].sum=right-left+1;
 36         tree[ind].type=1;
 37         if(left!=right)
 38         {
 39             int mid=tree[ind].mid();
 40             build(left,mid,LL(ind));
 41             build(mid+1,right,RR(ind));
 42         }
 43     }
 44     void relax(int ind)
 45     {
 46         if(tree[ind].type)
 47         {
 48             tree[LL(ind)].fun(tree[ind].type);
 49             tree[RR(ind)].fun(tree[ind].type);
 50             tree[ind].type=0;
 51         }
 52     }
 53     void updata(int st,int ed,int ind,int type)///区间更新
 54     {
 55         int left=tree[ind].left,right=tree[ind].right;
 56         if(st<=left&&right<=ed)
 57             tree[ind].fun(type);
 58         else
 59         {
 60             relax(ind);
 61             int mid = tree[ind].mid();
 62             if(st<=mid)
 63                 updata(st,ed,LL(ind),type);
 64             if(ed>mid)
 65                 updata(st,ed,RR(ind),type);
 66             tree[ind].sum = tree[LL(ind)].sum + tree[RR(ind)].sum;
 67         }
 68     }
 69     int query(int st,int ed,int ind)///区间求和
 70     {
 71         int left=tree[ind].left,right=tree[ind].right;
 72         if(st<=left&&right<=ed) return tree[ind].sum;
 73         else
 74         {
 75             relax(ind);
 76             int mid=tree[ind].mid();
 77             int sum1=0,sum2=0;
 78             if(st<=mid) sum1=query(st,ed,LL(ind));
 79             if(ed> mid) sum2=query(st,ed,RR(ind));
 80             return sum1+sum2;
 81         }
 82     }
 83 } seg;
 84 int main()
 85 {
 86     int t,t_cnt=0;
 87     scanf("%d",&t);
 88     while(t--)
 89     {
 90         int n,m,a,b,c;
 91         scanf("%d%d",&n,&m);
 92         seg.build(1,n,1);
 93         while(m--)
 94         {
 95             scanf("%d%d%d",&a,&b,&c);
 96             seg.updata(a,b,1,c);
 97         }
 98         printf("Case %d: The total value of the hook is %d.\n",++t_cnt,seg.query(1,n,1));
 99     }
100     return 0;
101 }
View Code

还有今天做的题,偏偏找了一个错的模板,改了2个小时。。。真是愚蠢

HDU5023:区间改值,查询区间内不同的具体数字(并不是个数),比如1 2 3 3 2 区间1~5内查询答案是1 2 3

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<set>
  4 #include<algorithm>
  5 using namespace std;
  6 #define lson l, mid, root<<1
  7 #define rson mid+1, r, root<<1|1
  8 const int N = 1e6 + 5;
  9 set <int> s;
 10 set <int> ::iterator it;
 11 struct Node
 12 {
 13     int color;
 14     int left;
 15     int right;
 16     int mid;
 17 } a[N<<2];
 18 
 19 void Push_Down(int root)
 20 {
 21     if(a[root].color)
 22     {
 23         a[root<<1].color = a[root].color;
 24         a[root<<1|1].color = a[root].color;
 25         a[root].color = 0;
 26     }
 27 }
 28 void Build_Tree(int l, int r, int root)
 29 {
 30     int mid = (l + r) >> 1;
 31     a[root].left = l;
 32     a[root].right = r;
 33     a[root].mid = mid;
 34     a[root].color = 2;
 35     if(l == r) return;
 36     Build_Tree(lson);
 37     Build_Tree(rson);
 38 }
 39 void Update(int l, int r, int c, int root)
 40 {
 41     if(a[root].left == l && a[root].right == r)
 42     {
 43         a[root].color = c;
 44         return;
 45     }
 46     if(a[root].color == c) return;
 47     Push_Down(root);
 48     if(l > a[root].mid) Update(l, r, c, root<<1|1);
 49     else if(r <= a[root].mid) Update(l, r, c, root<<1);
 50     else
 51     {
 52         Update(l, a[root].mid, c, root<<1);
 53         Update(a[root].mid+1, r, c, root<<1|1);
 54     }
 55 }
 56 void Query(int l, int r, int root)
 57 {
 58     if(a[root].color)
 59     {
 60         s.insert(a[root].color);
 61         return ;
 62     }
 63     if(l > a[root].mid) Query(l, r, root<<1|1);
 64     else if(r <= a[root].mid) Query(l, r, root<<1);
 65     else
 66     {
 67         Query(l, a[root].mid, root<<1);
 68         Query(a[root].mid+1, r, root<<1|1);
 69     }
 70 }
 71 int main()
 72 {
 73     int n, m;
 74     int l, r, c;
 75     char op[10];
 76     while(~scanf("%d%d", &n, &m) && (n + m))
 77     {
 78         Build_Tree(1, n, 1);
 79         for(int i = 0; i < m; i++)
 80         {
 81             scanf("%s%d%d", op, &l, &r);
 82             if(op[0] == 'P')
 83             {
 84                 scanf("%d", &c);
 85                 Update(l, r, c, 1);
 86             }
 87             else
 88             {
 89                 s.clear();
 90                 Query(l, r, 1);
 91                 int ss = s.size();
 92                 for(it = s.begin(); it != s.end(); it++)
 93                 {
 94                     printf("%d", *it);
 95                     if(ss > 1) printf(" ");
 96                     ss--;
 97                 }
 98                 printf("\n");
 99             }
100         }
101     }
102     return 0;
103 }
View Code

POJ3468:区间修改,区间里的数加上c,区间求和;代码和上题中的build和fun函数不同。

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<set>
  4 #include<algorithm>
  5 using namespace std;
  6 #define lson l, mid, root<<1
  7 #define rson mid+1, r, root<<1|1
  8 const int N = 1e6 + 5;
  9 set <int> s;
 10 set <int> ::iterator it;
 11 struct Node
 12 {
 13     int color;
 14     int left;
 15     int right;
 16     int mid;
 17 } a[N<<2];
 18 
 19 void Push_Down(int root)
 20 {
 21     if(a[root].color)
 22     {
 23         a[root<<1].color = a[root].color;
 24         a[root<<1|1].color = a[root].color;
 25         a[root].color = 0;
 26     }
 27 }
 28 void Build_Tree(int l, int r, int root)
 29 {
 30     int mid = (l + r) >> 1;
 31     a[root].left = l;
 32     a[root].right = r;
 33     a[root].mid = mid;
 34     a[root].color = 2;
 35     if(l == r) return;
 36     Build_Tree(lson);
 37     Build_Tree(rson);
 38 }
 39 void Update(int l, int r, int c, int root)
 40 {
 41     if(a[root].left == l && a[root].right == r)
 42     {
 43         a[root].color = c;
 44         return;
 45     }
 46     if(a[root].color == c) return;
 47     Push_Down(root);
 48     if(l > a[root].mid) Update(l, r, c, root<<1|1);
 49     else if(r <= a[root].mid) Update(l, r, c, root<<1);
 50     else
 51     {
 52         Update(l, a[root].mid, c, root<<1);
 53         Update(a[root].mid+1, r, c, root<<1|1);
 54     }
 55 }
 56 void Query(int l, int r, int root)
 57 {
 58     if(a[root].color)
 59     {
 60         s.insert(a[root].color);
 61         return ;
 62     }
 63     if(l > a[root].mid) Query(l, r, root<<1|1);
 64     else if(r <= a[root].mid) Query(l, r, root<<1);
 65     else
 66     {
 67         Query(l, a[root].mid, root<<1);
 68         Query(a[root].mid+1, r, root<<1|1);
 69     }
 70 }
 71 int main()
 72 {
 73     int n, m;
 74     int l, r, c;
 75     char op[10];
 76     while(~scanf("%d%d", &n, &m) && (n + m))
 77     {
 78         Build_Tree(1, n, 1);
 79         for(int i = 0; i < m; i++)
 80         {
 81             scanf("%s%d%d", op, &l, &r);
 82             if(op[0] == 'P')
 83             {
 84                 scanf("%d", &c);
 85                 Update(l, r, c, 1);
 86             }
 87             else
 88             {
 89                 s.clear();
 90                 Query(l, r, 1);
 91                 int ss = s.size();
 92                 for(it = s.begin(); it != s.end(); it++)
 93                 {
 94                     printf("%d", *it);
 95                     if(ss > 1) printf(" ");
 96                     ss--;
 97                 }
 98                 printf("\n");
 99             }
100         }
101     }
102     return 0;
103 }
用上两题的模板为什么改不出来呢,摘自另一位大神

 

posted @ 2015-08-14 21:23  一麻袋码的玛侬  阅读(346)  评论(2编辑  收藏  举报