• string [线段树优化桶排]


    题意大概是给你一个字符串,1e5次修改,每次给一个区间升序排列或降序排列,最后输出这个字符串;

    其实是个挺裸的线段树优化题;但是我没有意识去结合桶排,扑该.....

    首先 1.40分算法

    O(NMlogN)

     1 inline void update(int k){
     2     for(int i=1;i<=26;++i){
     3         tmp[k].tong[i]=tmp[ls].tong[i]+tmp[rs].tong[i];
     4     }
     5 }
     6 
     7 void ud(int k,int l,int r,int L,int R){
     8     if(L<=l&&r<=R)return void();
     9     if(L<=mid)ud(ls,l,mid,L,R);
    10     if(R>mid)ud(rs,mid+1,r,L,R);
    11     update(k);
    12

    直接sort

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define val(x) (x-'a'+1)
     4 int s[100050],N,M;
     5 char S[100050];
     6 bool cmp1(int a,int b){return a<b;}
     7 bool cmp0(int a,int b){return a>b;}
     8 int main()
     9 {
    10     //freopen("da.in","r",stdin);
    11    // freopen("ac.out","w",stdout);
    12     scanf("%d%d",&N,&M);
    13     scanf("%s",S+1);
    14     for(int i=1;i<=N;++i)s[i]=val(S[i]);
    15     for(int i=1,l,r,opt;i<=M;++i){
    16         scanf("%d%d%d",&l,&r,&opt);
    17         if(!opt)sort(s+l,s+r+1,cmp0);
    18         else sort(s+l,s+r+1,cmp1);
    19        // if(clock()>999900)break;
    20     }
    21     char c;
    22     for(int i=1;i<=N;++i){
    23         c=s[i]+'a'-1;
    24         printf("%c",c);
    25     }
    26     printf("
    ");
    27 }

    其次 2.仍是40分算法:

    其实也是出题人没良心,我们可以直接桶排,复杂度O(NM);起码降下了一个log,但还是40分;

    代码就不提供了;

    最后 3.100分算法:

    思路:结合2.中的桶排思想,我们发现修改排序一次可以只有O(N)的复杂度,而N,M<=1e5,自然想到线段树优化桶排;

    而这样想的裸想法的复杂度是O(MNlogN)氧化钙!跟暴力一样!

    但是可以发现 你的数值N的值域是你的字母,那N就只有26啦;

    最后O(MlogN*26)

    分析一下  M是询问;  logN是线段树上的查询(合并桶而需查询你所修改的区域的桶来合成一个新的桶); 26是每次桶合并所需复杂度;

    好,接下来,我们每次修改一个区间进行排序,就是把对应区间的桶合并成一个新桶,然后用这个新桶进行区间修改,但是注意,这个区间修改一定不要去真的O(N)区间赋值

    那就成为了真正的O(NMlogN)了;

    那怎么办?

    我们可以打懒标记啊!别说你像我一样不会打标记......

    那我们就可以标记哪个区间被修改了然后访问到再down一下,最后一遍dfs来一次全down统计答案对吧;

    注意,这里down很长很长

     1 void down(int k){
     2     if(!tmp[k].lazy)return ;
     3     register int sz=len(ls),pl=0,pr=0;
     4     memset(tmp[ls].tong,0,sizeof(tmp[ls].tong));
     5     memset(tmp[rs].tong,0,sizeof(tmp[rs].tong));
     6     if(tmp[k].opt){
     7         for(int i=1;i<=26;++i){
     8             if(tmp[k].tong[i]<=sz)
     9             {
    10                 tmp[ls].tong[i]=tmp[k].tong[i],sz-=tmp[k].tong[i];
    11             }
    12             else {
    13                 tmp[ls].tong[i]=sz;sz=i;break;
    14             }
    15         }
    16         tmp[rs].tong[sz]=tmp[k].tong[sz]-tmp[ls].tong[sz];
    17         if(len(rs)==1&&tmp[rs].tong[sz]==1){pr=sz;}
    18         register int zs=len(rs)-tmp[rs].tong[sz];
    19         for(int i=sz+1;i<=26;++i){
    20             tmp[rs].tong[i]=tmp[k].tong[i];
    21             zs-=tmp[k].tong[i];
    22             if(!zs)break;
    23         }
    24     }
    25     else {
    26         for(int i=26;i>=1;--i){
    27             if(tmp[k].tong[i]<=sz)
    28             {
    29                 tmp[ls].tong[i]=tmp[k].tong[i],sz-=tmp[k].tong[i];
    30             }
    31             else {
    32                 tmp[ls].tong[i]=sz;sz=i;break;
    33             }
    34         }
    35         tmp[rs].tong[sz]=tmp[k].tong[sz]-tmp[ls].tong[sz];
    36         register int zs=len(rs)-tmp[rs].tong[sz];
    37         for(int i=sz-1;i>=1;--i){
    38             tmp[rs].tong[i]=tmp[k].tong[i];
    39             zs-=tmp[k].tong[i];
    40             if(!zs)break;
    41         }
    42     }
    43     if(tmp[ls].l!=tmp[ls].r)tmp[ls].lazy=1;
    44     else tmp[ls].lz=pl;tmp[ls].opt=tmp[k].opt;
    45     if(tmp[rs].l!=tmp[rs].r)tmp[rs].lazy=1;
    46     else tmp[rs].lz=pr;tmp[rs].opt=tmp[k].opt;
    47     tmp[k].lazy=0;tmp[k].opt=0;
    48 }

    当然我不像Deepin某一样缩行;

    其实这里的down就是把你线段树上这个节点的两个儿子所对应区间的桶重新赋值的过程,当然赋值一次需要O(52);

    Tip:

    还有一点特别容易错的就是

    记住每次把你对应修改的区间的桶合并后要立即修改对应区间的桶(区间修改):(这里lg这个vector存放的是你修改的区间的在线段树上的节点编号)

     1 void exch(int opt){
     2     sort(lg.begin(),lg.end(),cmp);
     3     for(int i=0,sz,tt=1,ts=26;i<lg.size();++i){
     4         sz=len(lg[i]);
     5         memset(tmp[lg[i]].tong,0,sizeof(tmp[lg[i]].tong));
     6         if(opt){
     7             for(;tt<=26;++tt){
     8             if(sz>=ans[tt]){
     9                 sz-=ans[tt];
    10                 tmp[lg[i]].tong[tt]=ans[tt];
    11             }
    12             else {
    13                 tmp[lg[i]].tong[tt]=sz;
    14                 ans[tt]-=sz;break;
    15             }
    16             }
    17         }
    18         else {
    19             for(;ts>=1;--ts){
    20                         if(sz>=ans[ts]){
    21                             sz-=ans[ts];
    22                             tmp[lg[i]].tong[ts]=ans[ts];
    23                         }
    24                         else {
    25                             tmp[lg[i]].tong[ts]=sz;
    26                             ans[ts]-=sz;break;
    27                         }
    28             }
    29         }
    30     }
    31 }
    区间修改

    然后修改完后要立即把你这些修改的区间到根update一遍,毕竟你的懒标记只能维护儿子而不能维护父亲;

     1 inline void update(int k){
     2     for(int i=1;i<=26;++i){
     3         tmp[k].tong[i]=tmp[ls].tong[i]+tmp[rs].tong[i];
     4     }
     5 }
     6 
     7 
     8 void ud(int k,int l,int r,int L,int R){
     9     if(L<=l&&r<=R)return void();
    10     if(L<=mid)ud(ls,l,mid,L,R);
    11     if(R>mid)ud(rs,mid+1,r,L,R);
    12     update(k);
    13 }
    update

    然后附上代码

      1 #include<bits/stdc++.h>
      2 using namespace std;
      3 #define val(x) (x-'a'+1)
      4 #define mid (l+r>>1)
      5 #define ls (k<<1)
      6 #define rs (k<<1|1)
      7 #define len(x) (tmp[x].r-tmp[x].l+1)
      8 int s[100050],N,M;
      9 char S[100050];
     10 struct node{
     11    int l;int r;
     12    int tong[30];
     13    int lazy,lz,opt;
     14 }tmp[100050<<3];
     15 int ans[30];
     16 vector<int>lg;
     17 
     18 inline void update(int k){
     19     for(int i=1;i<=26;++i){
     20         tmp[k].tong[i]=tmp[ls].tong[i]+tmp[rs].tong[i];
     21     }
     22 }
     23 
     24 void down(int k){
     25     if(!tmp[k].lazy)return ;
     26     register int sz=len(ls),pl=0,pr=0;
     27     memset(tmp[ls].tong,0,sizeof(tmp[ls].tong));
     28     memset(tmp[rs].tong,0,sizeof(tmp[rs].tong));
     29     if(tmp[k].opt){
     30         for(int i=1;i<=26;++i){
     31             if(tmp[k].tong[i]<=sz)
     32             {
     33                 tmp[ls].tong[i]=tmp[k].tong[i],sz-=tmp[k].tong[i];
     34            //     if(len(ls)==1&&tmp[ls].tong[i]){pl=i;break;}
     35             }
     36             else {
     37                 tmp[ls].tong[i]=sz;sz=i;break;
     38             }
     39         }
     40         //for(int i=1;i<=sz-1;++i)tmp[rs].tong[i]=0;
     41         //for(int i=sz+1;i<=26;++i)tmp[ls].tong[i]=0;
     42         tmp[rs].tong[sz]=tmp[k].tong[sz]-tmp[ls].tong[sz];
     43         if(len(rs)==1&&tmp[rs].tong[sz]==1){pr=sz;}
     44         register int zs=len(rs)-tmp[rs].tong[sz];
     45         for(int i=sz+1;i<=26;++i){
     46             tmp[rs].tong[i]=tmp[k].tong[i];
     47             zs-=tmp[k].tong[i];
     48             if(!zs)break;
     49         //    if(len(rs)==1&&tmp[rs].tong[i]&&!pr)pr=i;
     50         }
     51     }
     52     else {
     53         for(int i=26;i>=1;--i){
     54             if(tmp[k].tong[i]<=sz)
     55             {
     56                 tmp[ls].tong[i]=tmp[k].tong[i],sz-=tmp[k].tong[i];
     57                // if(len(ls)==1&&tmp[ls].tong[i]){pl=i;break;}
     58             }
     59             else {
     60                 tmp[ls].tong[i]=sz;sz=i;break;
     61             }
     62         }
     63         //for(int i=26;i>=sz+1;--i)tmp[rs].tong[i]=0;
     64         //for(int i=1;i<=sz-1;++i)tmp[ls].tong[i]=0;
     65         tmp[rs].tong[sz]=tmp[k].tong[sz]-tmp[ls].tong[sz];
     66         //if(len(rs)==1&&tmp[rs].tong[sz]==1){pr=sz;}
     67         register int zs=len(rs)-tmp[rs].tong[sz];
     68         for(int i=sz-1;i>=1;--i){
     69             tmp[rs].tong[i]=tmp[k].tong[i];
     70             zs-=tmp[k].tong[i];
     71             if(!zs)break;
     72           //  if(len(rs)==1&&tmp[rs].tong[i]&&!pr)pr=i;
     73         }
     74     }
     75     if(tmp[ls].l!=tmp[ls].r)tmp[ls].lazy=1;
     76     else tmp[ls].lz=pl;tmp[ls].opt=tmp[k].opt;
     77     if(tmp[rs].l!=tmp[rs].r)tmp[rs].lazy=1;
     78     else tmp[rs].lz=pr;tmp[rs].opt=tmp[k].opt;
     79     tmp[k].lazy=0;tmp[k].opt=0;
     80 }
     81 
     82 inline void merge(int u,int opt){
     83     down(u);
     84     for(register int i=1;i<=26;++i){
     85         ans[i]+=tmp[u].tong[i];
     86     }
     87     if(len(u)>1)tmp[u].lazy=1;lg.push_back(u);
     88     tmp[u].opt=opt;
     89 }
     90 
     91 inline int zip(int k){
     92     //cout<<"laidao!"<<endl;
     93     for(int i=1;i<=26;++i)if(tmp[k].tong[i])return i;
     94 }
     95 
     96 void find(int k,int l,int r){
     97     if(l==r)return s[l]=zip(k),void();
     98     down(k);
     99     find(ls,l,mid);
    100     find(rs,mid+1,r);
    101 }
    102 
    103 void query(int k,int l,int r,int L,int R,int opt){
    104     if(L<=l&&r<=R)return merge(k,opt),void();
    105     down(k);
    106     if(L<=mid)query(ls,l,mid,L,R,opt);
    107     if(R>mid)query(rs,mid+1,r,L,R,opt);
    108 }
    109 
    110 void ud(int k,int l,int r,int L,int R){
    111     if(L<=l&&r<=R)return void();
    112     if(L<=mid)ud(ls,l,mid,L,R);
    113     if(R>mid)ud(rs,mid+1,r,L,R);
    114     update(k);
    115 }
    116 
    117 void building(int k,int l,int r){
    118     tmp[k].l=l;tmp[k].r=r;
    119     if(l==r)return  tmp[k].l=tmp[k].r=l,tmp[k].tong[s[l]]=1,tmp[k].lazy=tmp[k].opt=0,void();
    120     building(ls,l,mid);building(rs,mid+1,r);
    121     update(k);
    122 }
    123 
    124 bool cmp(int u,int v){return tmp[u].l<tmp[v].l;}
    125 
    126 void exch(int opt){
    127     sort(lg.begin(),lg.end(),cmp);
    128     for(int i=0,sz,tt=1,ts=26;i<lg.size();++i){
    129         sz=len(lg[i]);
    130         memset(tmp[lg[i]].tong,0,sizeof(tmp[lg[i]].tong));
    131         if(opt){
    132             for(;tt<=26;++tt){
    133             if(sz>=ans[tt]){
    134                 sz-=ans[tt];
    135                 tmp[lg[i]].tong[tt]=ans[tt];
    136             }
    137             else {
    138                 tmp[lg[i]].tong[tt]=sz;
    139                 ans[tt]-=sz;break;
    140             }
    141             }
    142         }
    143         else {
    144             for(;ts>=1;--ts){
    145                         if(sz>=ans[ts]){
    146                             sz-=ans[ts];
    147                             tmp[lg[i]].tong[ts]=ans[ts];
    148                         }
    149                         else {
    150                             tmp[lg[i]].tong[ts]=sz;
    151                             ans[ts]-=sz;break;
    152                         }
    153             }
    154         }
    155     }
    156 }
    157 int main()
    158 {
    159     //freopen("da.in","r",stdin);
    160     //freopen("te.out","w",stdout);
    161     scanf("%d%d",&N,&M);
    162     scanf("%s",S+1);
    163     for(int i=1;i<=N;++i)s[i]=val(S[i]);
    164     building(1,1,N);
    165     for(int i=1,l,r,opt;i<=M;++i){
    166         scanf("%d%d%d",&l,&r,&opt);
    167         memset(ans,0,sizeof(ans));lg.clear();
    168         query(1,1,N,l,r,opt);
    169         exch(opt);
    170         ud(1,1,N,l,r);
    171     }
    172     find(1,1,N);
    173     char c;
    174     for(int i=1;i<=N;++i){
    175         c=s[i]+'a'-1;
    176         printf("%c",c);
    177     }
    178     printf("
    ");
    179     //int ppx='P'-'a'+1;
    180     //cout<<"ppx="<<ppx<<endl;
    181 }
    ac
  • 相关阅读:
    JavaScript 命名空间
    雅虎网站页面性能优化的34条黄金守则
    利用模板引擎配合ajax进行数据的导入
    canvas 实现小人的行走和上下左右的变换
    canvas 做一个小鸟运动的小游戏 (第二步) 使小鸟飞起来
    canvas 做一个小鸟运动的小游戏 (第一步)
    canvas 画一个小时钟
    更改博客的通知
    pat advanced 1139. First Contact (30)
    10分钟上手python pandas
  • 原文地址:https://www.cnblogs.com/wang-hesong/p/11286548.html
Copyright © 2020-2023  润新知