3.2 区间信息的维护与查询

 例题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\n",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\n",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:\n",cas++);
128         for(int i=0;i<m;i++){
129             printf("%d %d\n",q[i].answer.first,q[i].answer.second);
130         }
131     }
132     return 0;
133 }
View Code

 

 

 例题10 uva11992 http://acm.hust.edu.cn/vjudge/problem/18697

对r*c的矩阵执行3个操作,子矩阵每个元素+v ,  子矩阵每个元素赋值 v。 查询一个子矩阵元素和, 最大值,最小值。

由于最多20行,可以每行一个一维线段树。

线段树多两个标记,一个标记区间+,一个标记区间赋值。更新的时候,赋值操作会清零+操作的累计值。

 

  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\n",q[i].sum,q[i].small,q[i].big);
187         }
188     }
189     return 0;
190 }
View Code

 

 

 

end

 

posted on 2016-08-09 23:03  gaolzzxin  阅读(259)  评论(0编辑  收藏  举报