线段树基础
题集: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 }
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 }
还有今天做的题,偏偏找了一个错的模板,改了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 }
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 }
人生就像心电图,想要一帆风顺,除非game-over