zoukankan      html  css  js  c++  java
  • 2015 Multi-University Training Contest 2 hdu 5306 Gorgeous Sequence

    Gorgeous Sequence

    Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)
    Total Submission(s): 349    Accepted Submission(s): 57


    Problem Description
    There is a sequence a of length n. We use ai to denote the i-th element in this sequence. You should do the following three types of operations to this sequence.

    0 x y t: For every xiy, we use min(ai,t) to replace the original ai's value.
    1 x y: Print the maximum value of ai that xiy.
    2 x y: Print the sum of ai that xiy.
     
    Input
    The first line of the input is a single integer T, indicating the number of testcases.

    The first line contains two integers n and m denoting the length of the sequence and the number of operations.

    The second line contains n separated integers a1,,an (1in,0ai<231).

    Each of the following m lines represents one operation (1xyn,0t<231).

    It is guaranteed that T=100n1000000, m1000000.
     
    Output
    For every operation of type 1 or 2, print one line containing the answer to the corresponding query.
     
    Sample Input
    1
    5 5
    1 2 3 4 5
    1 1 5
    2 1 5
    0 3 5 3
    1 1 5
    2 1 5
     
    Sample Output
    5
    15
    3
    12
    Hint
    Please use efficient IO method
     
    Source
     
    解题:线段树,对着标程写的,还是没搞清到底是怎么回事
     
     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 typedef long long LL;
     4 const int maxn = 1000010;
     5 struct node {
     6     int cover,s,tag,maxtag,maxv;
     7     LL sum;
     8 } tree[maxn<<2];
     9 node put(node c,int t) {
    10     if(!t) return c;
    11     if(c.cover != c.s) c.maxv = t;
    12     c.maxtag = t;
    13     c.sum += (LL)t*(c.s - c.cover);
    14     c.cover = c.s;
    15     return c;
    16 }
    17 node calc(const node &a,const node &b,int t) {
    18     node c;
    19     c.tag = t;
    20     c.s = a.s + b.s;
    21     c.sum = a.sum + b.sum;
    22     c.cover = a.cover + b.cover;
    23     c.maxv = max(a.maxv,b.maxv);
    24     c.maxtag = max(a.maxtag,b.maxtag);
    25     return put(c,t);
    26 }
    27 int tmp,n,m;
    28 void build(int L,int R,int v) {
    29     tree[v].tag = 0;
    30     tree[v].s = R - L + 1;
    31     if(L == R) {
    32         scanf("%d",&tmp);
    33         tree[v].sum = tree[v].tag = tree[v].maxtag = tree[v].maxv = tmp;
    34         tree[v].cover = 1;
    35         return;
    36     }
    37     int mid = (L + R)>>1;
    38     build(L,mid,v<<1);
    39     build(mid+1,R,v<<1|1);
    40     tree[v] = calc(tree[v<<1],tree[v<<1|1],0);
    41 }
    42 node query(int L,int R,int lt,int rt,int v) {
    43     if(lt <= L && rt >= R) return tree[v];
    44     int mid = (L + R)>>1;
    45     if(rt <= mid) return put(query(L,mid,lt,rt,v<<1),tree[v].tag);
    46     if(lt > mid) return put(query(mid+1,R,lt,rt,v<<1|1),tree[v].tag);
    47     return calc(query(L,mid,lt,rt,v<<1),query(mid+1,R,lt,rt,v<<1|1),tree[v].tag);
    48 }
    49 void cleartag(int v,int t) {
    50     if(tree[v].maxtag < t) return;
    51     if(tree[v].tag >= t) tree[v].tag = 0;
    52     if(tree[v].s > 1) {
    53         cleartag(v<<1,t);
    54         cleartag(v<<1|1,t);
    55     }
    56     if(tree[v].s == 1) {
    57         tree[v].sum = tree[v].maxtag = tree[v].maxv = tree[v].tag;
    58         tree[v].cover = (tree[v].tag > 0);
    59     } else tree[v] = calc(tree[v<<1],tree[v<<1|1],tree[v].tag);
    60 }
    61 void update(int L,int R,int lt,int rt,int t,int v) {
    62     if(tree[v].tag && tree[v].tag <= t) return;
    63     if(lt <= L && rt >= R) {
    64         cleartag(v,t);
    65         tree[v].tag = t;
    66         if(L == R) {
    67             tree[v].sum = tree[v].tag = tree[v].maxv = tree[v].maxtag = t;
    68             tree[v].cover = (tree[v].tag > 0);
    69         } else tree[v] = calc(tree[v<<1],tree[v<<1|1],t);
    70     } else {
    71         int mid = (L + R)>>1;
    72         if(rt <= mid) update(L,mid,lt,rt,t,v<<1);
    73         else if(lt > mid) update(mid+1,R,lt,rt,t,v<<1|1);
    74         else {
    75             update(L,mid,lt,rt,t,v<<1);
    76             update(mid+1,R,lt,rt,t,v<<1|1);
    77         }
    78         tree[v] = calc(tree[v<<1],tree[v<<1|1],tree[v].tag);
    79     }
    80 }
    81 int main() {
    82     int kase,op,x,y,t;
    83     scanf("%d",&kase);
    84     while(kase--) {
    85         scanf("%d%d",&n,&m);
    86         build(1,n,1);
    87         while(m--) {
    88             scanf("%d%d%d",&op,&x,&y);
    89             if(!op) {
    90                 scanf("%d",&t);
    91                 update(1,n,x,y,t,1);
    92             } else if(op == 1) printf("%d
    ",query(1,n,x,y,1).maxv);
    93             else printf("%I64d
    ",query(1,n,x,y,1).sum);
    94         }
    95     }
    96     return 0;
    97 }
    View Code

    哥终于搞清了,感谢 某岛 的代码

    本题的做法有点类似于天龙八部里面虚竹那个下棋场景,死而后生

    做法就是:每次更新一段区间的时候,把标记放到本区间,然后,我们要兵马未动,粮草先行

    先去下面走一遭,统计下面有多少个不大于t,并且这些不大于t的元素的和

    这样就能计算出当前区间的和了?不能?那么最大值呢?别逗了,当前区间的最大值肯定是t啦。

    tag?要么就是0,要么就是区间的最大值。不是么?

    你说这样都不超时真没天理?是的,我也是这么觉得的。。。每次都推到底,这还不超时。。。我也不知道分摊是如何分摊的

    下面是搞清真相后写的另一份代码,代码内附有注释,我想这是你目前所能看到的最详细的解说了,毕竟中学生写的代码,可能是有代沟吧

      1 #include <bits/stdc++.h>
      2 using namespace std;
      3 typedef long long LL;
      4 const int maxn = 1001010;
      5 struct node{
      6     LL sum;
      7     int cv,mx,tag;
      8     //cv用来记录该区间有多少个数不大于t
      9     //mx当然是记录区间的最大值
     10     //tag是lazy标识啦,这个线段树常客
     11     //sum...
     12 }tree[maxn<<2];
     13 void pushup(int v){
     14     tree[v].sum = tree[v<<1].sum + tree[v<<1|1].sum;
     15     tree[v].mx = max(tree[v<<1].mx,tree[v<<1|1].mx);
     16     tree[v].cv = tree[v<<1].cv + tree[v<<1|1].cv;
     17 }
     18 int tmp;
     19 void build(int lt,int rt,int v){
     20     if(lt == rt){
     21         scanf("%d",&tmp);
     22         tree[v].sum = tree[v].mx = tree[v].tag = tmp;
     23         tree[v].cv = 1;
     24         //cv记录的是不大于t的元素个数
     25         return;
     26     }
     27     tree[v].tag = 0;
     28     int mid = (lt + rt)>>1;
     29     build(lt,mid,v<<1);
     30     build(mid+1,rt,v<<1|1);
     31     pushup(v);
     32 }
     33 void modify(int L,int R,int t,int v){
     34     if(tree[v].tag && tree[v].tag <= t) return;
     35     tree[v].tag = t;
     36     //只有可能是tree[v].tag  == 0
     37     //因为前面calc的时候已经先行走了一遍
     38     if(tree[v].cv != R - L + 1){
     39         //因为当前区间不大于t的元素不算全区间,所以还有比t大的
     40         //大的要置成t,所以mx成了t
     41         tree[v].mx = t;
     42         tree[v].sum += (LL)t*(R - L + 1 - tree[v].cv);
     43         tree[v].cv = R - L + 1;
     44         //sum在alc以后 其实代表的是那些不大于t的元素之和
     45         //现在把大于t的都改成t了,那么现在和是多少?
     46     }
     47 }
     48 void pushdown(int L,int R,int v){
     49     if(tree[v].tag){
     50         int mid = (L + R)>>1;
     51         modify(L,mid,tree[v].tag,v<<1);
     52         modify(mid+1,R,tree[v].tag,v<<1|1);
     53         tree[v].tag = 0;
     54     }
     55 }
     56 void calc(int L,int R,int t,int v){
     57     if(tree[v].mx < t) return;
     58     if(tree[v].tag >= t) tree[v].tag = 0;
     59     if(L == R){
     60         tree[v].sum = tree[v].mx = tree[v].tag;
     61         tree[v].cv = tree[v].tag?1:0;
     62         //记录当前不大于t的元素的个数以及他们的和
     63         return;
     64     }
     65     pushdown(L,R,v);
     66     int mid = (L + R)>>1;
     67     calc(L,mid,t,v<<1);
     68     calc(mid+1,R,t,v<<1|1);
     69     pushup(v);
     70 }
     71 void update(int L,int R,int lt,int rt,int t,int v){
     72     if(tree[v].mx <= t) return;
     73     if(lt <= L && rt >= R){
     74         if(L == R){
     75             tree[v].sum = tree[v].tag = tree[v].mx = t;
     76             tree[v].cv = 1;
     77             //强行修改为t,毕竟此处是大于t的,如果不大于t前面return了
     78         }else calc(L,R,t,v);//先行遍历到底,兵马未动,粮草先行
     79         modify(L,R,t,v);
     80     }else{
     81         pushdown(L,R,v);
     82         int mid = (L + R)>>1;
     83         if(lt <= mid) update(L,mid,lt,rt,t,v<<1);
     84         if(rt > mid) update(mid+1,R,lt,rt,t,v<<1|1);
     85         pushup(v);
     86     }
     87 }
     88 int queryMax(int L,int R,int lt,int rt,int v){
     89     if(lt <= L && rt >= R) return tree[v].mx;
     90     int mid = (L + R)>>1,mx = INT_MIN;
     91     pushdown(L,R,v);
     92     if(lt <= mid) mx = max(mx,queryMax(L,mid,lt,rt,v<<1));
     93     if(rt > mid) mx = max(mx,queryMax(mid+1,R,lt,rt,v<<1|1));
     94     pushup(v);
     95     return mx;
     96 }
     97 LL querySum(int L,int R,int lt,int rt,int v){
     98     if(lt <= L && rt >= R) return tree[v].sum;
     99     int mid = (L + R)>>1;
    100     LL sum = 0;
    101     pushdown(L,R,v);
    102     if(lt <= mid) sum += querySum(L,mid,lt,rt,v<<1);
    103     if(rt > mid) sum += querySum(mid+1,R,lt,rt,v<<1|1);
    104     pushup(v);
    105     return sum;
    106 }
    107 int main(){
    108     int kase,n,m,op,x,y,t;
    109     scanf("%d",&kase);
    110     while(kase--){
    111         scanf("%d%d",&n,&m);
    112         build(1,n,1);
    113         while(m--){
    114             scanf("%d%d%d",&op,&x,&y);
    115             if(x > y) swap(x,y);
    116             if(!op){
    117                 scanf("%d",&t);
    118                 update(1,n,x,y,t,1);
    119             }else if(op == 1) printf("%d
    ",queryMax(1,n,x,y,1));
    120             else printf("%I64d
    ",querySum(1,n,x,y,1));
    121         }
    122     }
    123     return 0;
    124 }
    View Code
  • 相关阅读:
    shell中十种实现自加的方法
    expect 安装使用
    wireshark常用过滤规则
    linux错误收集
    18.socket概述
    17.异常处理/模块与包
    15.常用模块【time/os/sys】
    14.继承与授权
    13.面向对象(多态/(性)/封装)
    11.高阶函数(匿名/*递归/函数式)对象编程基础
  • 原文地址:https://www.cnblogs.com/crackpotisback/p/4677511.html
Copyright © 2011-2022 走看看