1. 程式人生 > 實用技巧 >Redis-Redis及其持久化。

Redis-Redis及其持久化。

感謝卡老師上課分享的題單

CF558E

題意

Luogu
給定一個長度不超過10^5的字串(小寫英文字母),和不超過50000個操作。
每個操作 L R K 表示給區間[L,R]的字串排序,K=1為升序,K=0為降序。
輸出最終的字串。

題解

因為字符集只有26,所以區間內重複元素個數很多,排序後相同元素會聚攏,即區間覆蓋
考慮用線段樹記錄區間內每個字母出現的次數,然後按序區間覆蓋即可

程式碼

#include<bits/stdc++.h>
using namespace std;
#define re register
#define ll long long
#define get getchar()
#define in inline
in int read()
{
    int t=0, x=1; char ch=get;
    while((ch<'0' || ch>'9') && ch!='-')ch=get;
    if(ch=='-') ch=get, x=-1;
    while(ch<='9' && ch>='0') t=t*10+ch-'0', ch=get;
    return x*t;
}
const int _=1e5+5;
int n,m;
char s[_];
int t[_<<3][27],la[_<<3],ans[27];
in void add(int k,int l,int r,int x,int y)
{
    if(l==r) {
        t[k][y]++;
        return;
    }
    int mid=l+r>>1;
    if(x<=mid) add(k<<1, l, mid, x, y);
    else add(k<<1|1, mid+1, r, x, y);
    t[k][y]=t[k<<1][y]+t[k<<1|1][y];
}
in void pushdown(int k,int l,int r)
{
    if(la[k]==0) return ;
    la[k<<1]=la[k<<1|1]=la[k];
    for(re int i=1;i<=26;i++) t[k<<1][i]=t[k<<1|1][i]=0;
    int mid=l+r>>1;
    t[k<<1][la[k]]=mid-l+1;
    t[k<<1|1][la[k]]=r-mid;
    la[k]=0;
}
in void query(int k,int l,int r,int x,int y)
{
    if(x<=l && r<=y)
    {
        for(re int i=1;i<=26;i++) ans[i]+=t[k][i];
        return;
    }
    int mid=l+r>>1;
    pushdown(k,l,r);
    if(x<=mid) query(k<<1, l, mid, x, y);
    if(y>mid) query(k<<1|1, mid+1, r, x, y);
}
in void update(int k,int l,int r,int x,int y,int z)
{
    if(x<=l && r<=y) {
        for(re int i=1;i<=26;i++) t[k][i]=0;
        t[k][z]=r-l+1;
        la[k]=z;
        return;
    }
    pushdown(k,l,r);
    int mid=l+r>>1;
    if(x<=mid) update(k<<1, l, mid, x, y, z);
    if(y>mid) update(k<<1|1, mid+1, r, x, y, z);
    for(re int i=1;i<=26;i++) t[k][i]=t[k<<1][i]+t[k<<1|1][i];
}
int main()
{
    n=read(), m=read();
    scanf("%s",s+1);
    for(re int i=1;i<=n;i++) add(1,1,n,i,s[i]-'a'+1);
    for(re int i=1;i<=m;i++)
    {
        int l=read(), r=read(), z=read();
        query(1,1,n,l,r);
        int p=l;
        if(z==1)
            for(re int j=1;j<=26;j++)
            {
                if(ans[j]==0) continue;
                update(1,1,n,p,p+ans[j]-1,j);
                p+=ans[j];
            }
        else
            for(re int j=26;j>=1;j--)
            {
                if(ans[j]==0) continue;
                update(1,1,n,p,p+ans[j]-1,j);
                p+=ans[j];
            }
        memset(ans,0,sizeof(ans));
    }
    for(re int i=1;i<=n;i++)
    {
        query(1,1,n,i,i);
        int k=0;
        for(re int j=1;j<=26;j++) if(ans[j]) {k=j;break;}
        //極其愚蠢的輸出方式:查詢每個點的字符集,找那個字元有值/kk
        ans[k]=0;
        printf("%c",char(k-1+'a')); 
    }
    return 0;
}

CF438D

題意

Luogu
給定數列,區間查詢和,區間取模,單點修改。

題解

老套路了
因為取模次數有限,最多log次
考慮暴力修改,並記錄區間最大值,當最大值小於模數時直接跳過

#include<bits/stdc++.h>
using namespace std;
#define re register
#define ll long long
#define get getchar()
#define in inline
in int read()
{
    int t=0, x=1; char ch=get;
    while((ch<'0' || ch>'9') && ch!='-') ch=get;
    if(ch=='-') ch=get, x=-1;
    while(ch<='9'  && ch>='0') t=t*10+ch-'0', ch=get;
    return t*x;
}
const int _=2e5+1;
int n,m,mx[_<<4];
ll sum[_<<4];
in void pushup(int k)
{
    sum[k]=sum[k<<1]+sum[k<<1|1];
    mx[k]=max(mx[k<<1],mx[k<<1|1]);
}
in void add(int k,int l,int r,int x,int y)
{
    if(l==r)
    {
        mx[k]=sum[k]=y;
        return ;
    }
    int mid=l+r>>1;
    if(x<=mid) add(k<<1, l, mid, x, y);
    else add(k<<1|1, mid+1, r, x, y);
    pushup(k);
}
in void mod(int k,int l,int r,int x,int y,int p)
{
    if(mx[k]<p) return; //區間最大值小於模數
    if(l==r)
    {
        mx[k]=sum[k]%=p;
        return;
    }
    int mid= l+r>>1;
    if(x<=mid) mod(k<<1, l, mid, x, y, p);
    if(y>mid) mod(k<<1|1, mid+1, r, x, y, p);
    pushup(k);
}
in ll query(int k,int l,int r,int x,int y)
{
    if(x<=l && r<=y) return sum[k];
    int mid=l+r>>1;
    ll s=0;
    if(x<=mid) s+=query(k<<1, l, mid, x, y);
    if(y>mid) s+=query(k<<1|1, mid+1, r, x, y);
    return s;
}
int main()
{
    n=read(), m=read();
    for(re int i=1;i<=n;i++) add(1,1,n,i,read());
    for(re int i=1;i<=m;i++)
    {
        int opt=read();
        if(opt==1) {
            int l=read(), r=read();
            printf("%lld\n",query(1,1,n,l,r));
        }
        if(opt==2) {
            int l=read(), r=read(), p=read();
            mod(1,1,n,l,r,p);
        }
        if(opt==3) {
            int x=read(), y=read();
            add(1,1,n,x,y);
        }
    }
    return 0;
}