3.2 区间信息的维护与查询
分类:
IT文章
•
2023-11-05 22:26:41
例题7 la 4329 http://acm.hust.edu.cn/vjudge/problem/13895
每个人有能力值, 一场比赛需要3个人, 要求下标中间的人作为裁判 , 且中间的人的能力值 要在左右两个人之间 ,问共能进行多少场比赛.
树状数组统计某个人前面有多少比他小的, 前大, 后小 后大, 情况等于 前面小* 后面大 或者前面大*后面小.
1 //#define txtout
2 //#define debug
3 #include<bits/stdc++.h>
4 #define mt(a,b) memset(a,b,sizeof(a))
5 using namespace std;
6 typedef long long LL;
7 const double pi=acos(-1.0);
8 const double eps=1e-8;
9 const int inf=0x3f3f3f3f;
10 const int M=1e5+10;
11 class One_Tree_Array { ///一维树状数组
12 static const int M=1e5+10; ///点的个数
13 typedef int typev;
14 typev a[M];
15 int n;
16 public:
17 void init(int tn) { ///传入点数,点下标 1 开始
18 n=tn;
19 for(int i=0; i<=n; i++) a[i]=0;
20 }
21 int lowb(int t) {
22 return t&(-t);
23 }
24 void add(int i,typev v) {
25 for(; i<=n; a[i]+=v,i+=lowb(i));
26 }
27 typev sum(int i) {
28 typev s=0;
29 for(; i>0; s+=a[i],i-=lowb(i));
30 return s;
31 }
32 } tree;
33 int n;
34 int a[M];
35 LL frontSmall[M];
36 LL frontBig[M];
37 LL backSmall[M];
38 LL backBig[M];
39 LL solve() {
40 int big=1e5;
41 tree.init(big);
42 for(int i=0;i<n;i++){
43 frontSmall[i]=tree.sum(a[i]);
44 frontBig[i]=tree.sum(big)-tree.sum(a[i]);
45 tree.add(a[i],1);
46 }
47 tree.init(big);
48 for(int i=n-1;i>=0;i--){
49 backSmall[i]=tree.sum(a[i]);
50 backBig[i]=tree.sum(big)-tree.sum(a[i]);
51 tree.add(a[i],1);
52 }
53 LL sum=0;
54 for(int i=0;i<n;i++){
55 sum+=frontSmall[i]*backBig[i];
56 sum+=frontBig[i]*backSmall[i];
57 }
58 return sum;
59 }
60 int main() {
61 #ifdef txtout
62 freopen("in.txt","r",stdin);
63 freopen("out.txt","w",stdout);
64 #endif // txtout
65 int t;
66 while(~scanf("%d",&t)) {
67 while(t--) {
68 scanf("%d",&n);
69 for(int i=0; i<n; i++) {
70 scanf("%d",&a[i]);
71 }
72 printf("%lld
",solve());
73 }
74 }
75 return 0;
76 }
View Code
例题8 uva11235 http://acm.hust.edu.cn/vjudge/problem/23846
给一个不减序列,每次查询一个区间中,出现次数最多的数, 输出次数.
预处理,把相同的数分到同一组,记录每组的个数和起点的下标, 对于查询的下标, 可以二分出哪几组在这个区间内, 完全在区间内的可以直接通过rmq查出个数的最大值, 两端部分在区间内的, 可以直接计算.
1 //#define txtout
2 //#define debug
3 #include<bits/stdc++.h>
4 #define mt(a,b) memset(a,b,sizeof(a))
5 using namespace std;
6 typedef long long LL;
7 const double pi=acos(-1.0);
8 const double eps=1e-8;
9 const int inf=0x3f3f3f3f;
10 const int M=1e5+10;
11 class RMQ { ///区间最值查询(ST)离线算法 init O(n*logn) query O(1)
12 typedef int typec; ///点权类型
13 static const int M=1e5+10; ///点的个数
14 int LOG[M];
15 typec dpmax[M][20],dpmin[M][20];
16 public:
17 RMQ() {
18 LOG[0]=-1;
19 for(int i=1; i<M; i++) {
20 LOG[i]=LOG[i>>1]+1;
21 }
22 }
23 void init(int n,typec a[]) { ///传入点的个数,下标 1 开始
24 for(int i=1; i<=n; i++) {
25 dpmax[i][0]=dpmin[i][0]=a[i];
26 }
27 for(int j=1; j<=LOG[n]; j++) {
28 for(int i=1; i+(1<<j)-1<=n; i++) {
29 int k=i+(1<<(j-1));
30 dpmax[i][j]=max(dpmax[i][j-1],dpmax[k][j-1]);
31 dpmin[i][j]=min(dpmin[i][j-1],dpmin[k][j-1]);
32 }
33 }
34 }
35 typec get(int a,int b,bool big) { ///传入 1 返回 max,传入 0 返回 min
36 int k=LOG[b-a+1];
37 b=b-(1<<k)+1;
38 if(big) return max(dpmax[a][k],dpmax[b][k]);
39 return min(dpmin[a][k],dpmin[b][k]);
40 }
41 } rmq;
42 int n,m;
43 int a[M];
44 int number[M];
45 int id[M];
46 struct Q {
47 int x,y,answer;
48 } q[M];
49 int Binary(int value,int len){
50 int L=1,R=len,result=1;
51 while(L<=R){
52 int mid=(L+R)>>1;
53 if(id[mid]<=value){
54 result=mid;
55 L=mid+1;
56 }
57 else{
58 R=mid-1;
59 }
60 }
61 return result;
62 }
63 void solve() {
64 int last=0;
65 for(int i=1; i<=n; i++) {
66 if(last==0||a[i]!=a[id[last]]) {
67 last++;
68 id[last]=i;
69 number[last]=1;
70 continue;
71 }
72 number[last]++;
73 }
74 rmq.init(last,number);
75 for(int i=0;i<m;i++){
76 q[i].answer=1;
77 if(q[i].x==q[i].y) continue;
78 int l=Binary(q[i].x,last);
79 int r=Binary(q[i].y,last);
80 if(l==r){
81 q[i].answer=q[i].y-q[i].x+1;
82 continue;
83 }
84 if(id[l]<q[i].x){
85 q[i].answer=max(q[i].answer,id[l+1]-q[i].x);
86 l++;
87 }
88 q[i].answer=max(q[i].answer,q[i].y-id[r]+1);
89 r--;
90 if(l<=r){
91 q[i].answer=max(q[i].answer,rmq.get(l,r,1));
92 }
93 }
94 }
95 int main() {
96 #ifdef txtout
97 freopen("in.txt","r",stdin);
98 freopen("out.txt","w",stdout);
99 #endif // txtout
100 while(~scanf("%d",&n),n) {
101 scanf("%d",&m);
102 for(int i=1; i<=n; i++) {
103 scanf("%d",&a[i]);
104 }
105 for(int i=0; i<m; i++) {
106 scanf("%d%d",&q[i].x,&q[i].y);
107 }
108 solve();
109 for(int i=0; i<m; i++) {
110 printf("%d
",q[i].answer);
111 }
112 }
113 return 0;
114 }
View Code
例题9 LA3938 http://acm.hust.edu.cn/vjudge/problem/22105
做了好几天,这个题值得记。
给一个整数序列,查询一个区间[L,R]中,和最大的区间的起点和终点是多少,既找到 [x,y],满足x,y在 LR内, 且Ax+。。。Ay的和是LR中所有子段和中最大的,如果有多个sum相同,取x小的,如果还有多个x相同 ,取y小的。
线段树每个节点存4个值,start,end,就是这个区间的答案。 设该节点管辖范围 [L,R], leftend是从L开始累加到leftend,和最大的位置,如果有多个和相同,leftend保存最小的那个位置。
rightstart是 从rightstart开始累加到R,和最大的位置,如果有多个,还是保存最小的那个位置。
叶子节点四个值都相同。 其他节点由左右儿子pushup得到。 方法,和最大的子段有3种可能,完全在左儿子,完全在右儿子,由左儿子rightstart加到右儿子leftend。
从L开始,leftend有两种情况 , 一种还是左儿子的leftend, 一种是L一直加到右儿子的leftend, rightstart的更新同理。
查询我一直错,错在如果查询的区间在左右儿子都有的时候,不是简单的取个大的,还要考虑中间接在一起的情况。
1 //#define txtout
2 //#define debug
3 #include<bits/stdc++.h>
4 #define mt(a,b) memset(a,b,sizeof(a))
5 using namespace std;
6 typedef long long LL;
7 const double pi=acos(-1.0);
8 const double eps=1e-8;
9 const int inf=0x3f3f3f3f;
10 const int M=5e5+10;
11 typedef pair<int,int> pii;
12 LL sum[M];
13 class SegmentTree{
14 #define lrrt int L,int R,int rt
15 #define iall 1,n,1
16 #define imid int mid=(L+R)>>1
17 #define lson L,mid,rt<<1
18 #define rson mid+1,R,rt<<1|1
19 static const int MV=5e5+10;
20 struct T{
21 int Start,End,leftEnd,rightStart;
22 }tree[MV<<2];
23 int n;
24 pii getBest(pii a,pii b){
25 LL sa=sum[a.second]-sum[a.first-1];
26 LL sb=sum[b.second]-sum[b.first-1];
27 if(sa>sb) return a;
28 if(sa<sb) return b;
29 if(a.first<b.first) return a;
30 if(a.first>b.first) return b;
31 if(a.second<b.second) return a;
32 return b;
33 }
34 T combine(int L,int R,T l,T r){
35 pii a=make_pair(l.Start,l.End);
36 pii b=make_pair(r.Start,r.End);
37 pii c=make_pair(l.rightStart,r.leftEnd);
38 a=getBest(a,b);
39 a=getBest(a,c);
40 T result;
41 result.Start=a.first;
42 result.End=a.second;
43 a=make_pair(L,l.leftEnd);
44 b=make_pair(L,r.leftEnd);
45 result.leftEnd=getBest(a,b).second;
46 a=make_pair(l.rightStart,R);
47 b=make_pair(r.rightStart,R);
48 result.rightStart=getBest(a,b).first;
49 return result;
50 }
51 void pushup(lrrt){
52 tree[rt]=combine(L,R,tree[rt<<1],tree[rt<<1|1]);
53 }
54 void build(lrrt){
55 if(L==R){
56 tree[rt].Start=L;
57 tree[rt].End=L;
58 tree[rt].leftEnd=L;
59 tree[rt].rightStart=L;
60 return ;
61 }
62 imid;
63 build(lson);
64 build(rson);
65 pushup(L,R,rt);
66 }
67 T query(int x,int y,lrrt){
68 if(x<=L&&R<=y) return tree[rt];
69 T a,b;
70 bool f1=false,f2=false;
71 imid;
72 if(mid>=x){
73 a=query(x,y,lson);
74 f1=true;
75 }
76 if(mid<y){
77 b=query(x,y,rson);
78 f2=true;
79 }
80 if(!f1) return b;
81 if(!f2) return a;
82 return combine(x,y,a,b);
83 }
84 public:
85 void init(int tn){
86 n=tn;
87 build(iall);
88 }
89 pii query(int x,int y){
90 T result=query(x,y,iall);
91 return make_pair(result.Start,result.End);
92 }
93 }st;
94 int n,m;
95 int a[M];
96 struct Q{
97 int x,y;
98 pii answer;
99 }q[M];
100 void init_sum(){
101 sum[0]=0;
102 for(int i=1;i<=n;i++){
103 sum[i]=sum[i-1]+a[i];
104 }
105 }
106 void solve(){
107 init_sum();
108 st.init(n);
109 for(int i=0;i<m;i++){
110 q[i].answer=st.query(q[i].x,q[i].y);
111 }
112 }
113 int main(){
114 #ifdef txtout
115 freopen("in.txt","r",stdin);
116 freopen("out.txt","w",stdout);
117 #endif // txtout
118 int cas=1;
119 while(~scanf("%d%d",&n,&m)){
120 for(int i=1;i<=n;i++){
121 scanf("%d",&a[i]);
122 }
123 for(int i=0;i<m;i++){
124 scanf("%d%d",&q[i].x,&q[i].y);
125 }
126 solve();
127 printf("Case %d:
",cas++);
128 for(int i=0;i<m;i++){
129 printf("%d %d
",q[i].answer.first,q[i].answer.second);
130 }
131 }
132 return 0;
133 }
View Code
1 //#define txtout
2 //#define debug
3 #include<bits/stdc++.h>
4 #define mt(a,b) memset(a,b,sizeof(a))
5 using namespace std;
6 typedef long long LL;
7 const double pi=acos(-1.0);
8 const double eps=1e-8;
9 const int inf=0x3f3f3f3f;
10 const int M=2e4+10;
11 class SegmentTree{
12 #define lrrt int L,int R,int rt
13 #define iall 1,n,1
14 #define imid int mid=(L+R)>>1
15 #define lson L,mid,rt<<1
16 #define rson mid+1,R,rt<<1|1
17 static const int MV=1e6+10;
18 struct T{
19 int small,big,sum,lazy,cover;
20 }tree[MV<<2];
21 int n;
22 void build(lrrt){
23 tree[rt].small=0;
24 tree[rt].big=0;
25 tree[rt].sum=0;
26 tree[rt].lazy=0;
27 tree[rt].cover=0;
28 if(L==R) return ;
29 imid;
30 build(lson);
31 build(rson);
32 }
33 void pushup(int rt){
34 tree[rt].sum=tree[rt<<1].sum+tree[rt<<1|1].sum;
35 tree[rt].big=max(tree[rt<<1].big,tree[rt<<1|1].big);
36 tree[rt].small=min(tree[rt<<1].small,tree[rt<<1|1].small);
37 }
38 void pushdown(int mid,lrrt){
39 if(tree[rt].cover){
40 tree[rt<<1].cover=tree[rt].cover;
41 tree[rt<<1|1].cover=tree[rt].cover;
42 tree[rt<<1].big=tree[rt].cover;
43 tree[rt<<1|1].big=tree[rt].cover;
44 tree[rt<<1].small=tree[rt].cover;
45 tree[rt<<1|1].small=tree[rt].cover;
46 tree[rt<<1].sum=tree[rt].cover*(mid-L+1);
47 tree[rt<<1|1].sum=tree[rt].cover*(R-mid);
48 tree[rt<<1].lazy=0;
49 tree[rt<<1|1].lazy=0;
50 tree[rt].cover=0;
51 }
52 if(tree[rt].lazy){
53 tree[rt<<1].big+=tree[rt].lazy;
54 tree[rt<<1|1].big+=tree[rt].lazy;
55 tree[rt<<1].small+=tree[rt].lazy;
56 tree[rt<<1|1].small+=tree[rt].lazy;
57 tree[rt<<1].sum+=tree[rt].lazy*(mid-L+1);
58 tree[rt<<1|1].sum+=tree[rt].lazy*(R-mid);
59 tree[rt<<1].lazy+=tree[rt].lazy;
60 tree[rt<<1|1].lazy+=tree[rt].lazy;
61 tree[rt].lazy=0;
62 }
63 }
64 void update(int x,int y,int z,lrrt){
65 if(x<=L&&R<=y){
66 tree[rt].big+=z;
67 tree[rt].small+=z;
68 tree[rt].sum+=(R-L+1)*z;
69 tree[rt].lazy+=z;
70 return ;
71 }
72 imid;
73 pushdown(mid,L,R,rt);
74 if(mid>=x) update(x,y,z,lson);
75 if(mid<y) update(x,y,z,rson);
76 pushup(rt);
77 }
78 void change(int x,int y,int z,lrrt){
79 if(x<=L&&R<=y){
80 tree[rt].big=z;
81 tree[rt].small=z;
82 tree[rt].sum=(R-L+1)*z;
83 tree[rt].lazy=0;
84 tree[rt].cover=z;
85 return ;
86 }
87 imid;
88 pushdown(mid,L,R,rt);
89 if(mid>=x) change(x,y,z,lson);
90 if(mid<y) change(x,y,z,rson);
91 pushup(rt);
92 }
93 int querySum(int x,int y,lrrt){
94 if(x<=L&&R<=y) return tree[rt].sum;
95 imid;
96 pushdown(mid,L,R,rt);
97 int sum=0;
98 if(mid>=x) sum+=querySum(x,y,lson);
99 if(mid<y) sum+=querySum(x,y,rson);
100 return sum;
101 }
102 int queryMax(int x,int y,lrrt){
103 if(x<=L&&R<=y) return tree[rt].big;
104 imid;
105 pushdown(mid,L,R,rt);
106 int big=-1;
107 if(mid>=x) big=max(big,queryMax(x,y,lson));
108 if(mid<y) big=max(big,queryMax(x,y,rson));
109 return big;
110 }
111 int queryMin(int x,int y,lrrt){
112 if(x<=L&&R<=y) return tree[rt].small;
113 imid;
114 pushdown(mid,L,R,rt);
115 int small=inf;
116 if(mid>=x) small=min(small,queryMin(x,y,lson));
117 if(mid<y) small=min(small,queryMin(x,y,rson));
118 return small;
119 }
120 public:
121 void init(int tn){
122 n=tn;
123 build(iall);
124 }
125 void update(int x,int y,int z){
126 update(x,y,z,iall);
127 }
128 void change(int x,int y,int z){
129 change(x,y,z,iall);
130 }
131 int querySum(int x,int y){
132 return querySum(x,y,iall);
133 }
134 int queryMax(int x,int y){
135 return queryMax(x,y,iall);
136 }
137 int queryMin(int x,int y){
138 return queryMin(x,y,iall);
139 }
140 }st[21];
141 int r,c,m;
142 struct Q{
143 int type,x1,y1,x2,y2,v,sum,big,small;
144 }q[M];
145 void init(){
146 for(int i=1;i<=r;i++){
147 st[i].init(c);
148 }
149 }
150 void solve(){
151 init();
152 for(int i=0;i<m;i++){
153 q[i].sum=0;
154 q[i].big=-1;
155 q[i].small=inf;
156 for(int j=q[i].x1;j<=q[i].x2;j++){
157 if(q[i].type==1){
158 st[j].update(q[i].y1,q[i].y2,q[i].v);
159 }
160 else if(q[i].type==2){
161 st[j].change(q[i].y1,q[i].y2,q[i].v);
162 }
163 else{
164 q[i].sum+=st[j].querySum(q[i].y1,q[i].y2);
165 q[i].big=max(q[i].big,st[j].queryMax(q[i].y1,q[i].y2));
166 q[i].small=min(q[i].small,st[j].queryMin(q[i].y1,q[i].y2));
167 }
168 }
169 }
170 }
171 int main(){
172 #ifdef txtout
173 freopen("in.txt","r",stdin);
174 freopen("out.txt","w",stdout);
175 #endif // txtout
176 while(~scanf("%d%d%d",&r,&c,&m)){
177 for(int i=0;i<m;i++){
178 scanf("%d%d%d%d%d",&q[i].type,&q[i].x1,&q[i].y1,&q[i].x2,&q[i].y2);
179 if(q[i].type<3){
180 scanf("%d",&q[i].v);
181 }
182 }
183 solve();
184 for(int i=0;i<m;i++){
185 if(q[i].type!=3) continue;
186 printf("%d %d %d
",q[i].sum,q[i].small,q[i].big);
187 }
188 }
189 return 0;
190 }