• 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
    ",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

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

    end

  • 相关阅读:
    重置SQLSERVER表的自增列,让自增列重新计数
    【PLM】【PDM】60页PPT终于说清了PDM和PLM的区别;智造时代,PLM系统10大应用趋势!
    数据库设计规范
    不要听吹牛逼什么前端MVVM框架就是好,其实都是一帮没学好分层设计的搞出来的,让你彻底看清前端MVVM的本质
    SQL数据库日志清理
    1.3、安装MySQL、MySQLdb、Pycharm和其他软件
    1.2.2.3、Django虚拟目录作用以及文件说明
    nginx设置图片防盗链和白名单
    php-5.5.7升级,编译配置方法
    mysql函数CONCAT_WS()比CONCAT()更方便
  • 原文地址:https://www.cnblogs.com/gaolzzxin/p/5754952.html
Copyright © 2020-2023  润新知