zzzyc

导航

板子们~缓慢更新

1.树链剖分

#include<iostream>
#include<cstdio>
#define maxn 1000001
using namespace std;
int num,head[maxn],dep[maxn],fa[maxn],siz[maxn];
int son[maxn],id[maxn],cnt,wt[maxn],w[maxn],top[maxn];
int sum[maxn],mo,laz[maxn],n,res,m,number;

struct asd{
    int next;
    int to;
} a[maxn<<1];

inline void add(int x,int y)
{
    a[++num].next=head[x];
    a[num].to=y;
    head[x]=num;
}

inline void dfs1(int x,int father,int deep)
{
    dep[x]=deep; fa[x]=father; siz[x]=1;
    int maxson=-1;
    for(int i=head[x];i;i=a[i].next)
    {
        int to=a[i].to; if(to==father) continue;
        dfs1(to,x,deep+1);
        siz[x]+=siz[to];
        if(siz[to]>maxson)
        {
            son[x]=to;
            maxson=siz[to];
        }
    }
}

inline void dfs2(int x,int topp)
{
    id[x]=++cnt; wt[cnt]=w[x]; top[x]=topp;
    if(!son[x]) return;
    dfs2(son[x],topp);
    for(int i=head[x];i;i=a[i].next)
    {
        if(a[i].to==fa[x] || a[i].to==son[x])
            continue;
        dfs2(a[i].to,a[i].to);
    }
}

inline void build(int rt,int l,int r)
{
    if(l==r)
    {
        sum[rt]=wt[l];
        sum[rt]%=mo;
        return;
    }
    int mid=l+r>>1;
    build(rt<<1,l,mid);
    build(rt<<1|1,mid+1,r);
    sum[rt]=(sum[rt<<1]+sum[rt<<1|1])%mo;
}

inline void pushdown(int rt,int ln,int rn)
{
    if(laz[rt])
    {
        laz[rt<<1]+=laz[rt];
        laz[rt<<1|1]+=laz[rt];
        sum[rt<<1]+=laz[rt]*ln;
        sum[rt<<1|1]+=laz[rt]*rn;
        sum[rt<<1]%=mo;
        sum[rt<<1|1]%=mo;
        laz[rt]=0;
    }
}

inline void update(int rt,int l,int r,int L,int R,int k)
{
    if(L<=l && r<=R)
    {
        laz[rt]+=k;
        sum[rt]+=k*(r-l+1);
        return;
    }
    int mid=l+r>>1;
    pushdown(rt,mid-l+1,r-mid);
    if(L<=mid) update(rt<<1,l,mid,L,R,k);
    if(R>mid) update(rt<<1|1,mid+1,r,L,R,k);
    sum[rt]=(sum[rt<<1]+sum[rt<<1|1])%mo;
}

inline void change(int x,int y,int k)
{
    k%=mo;
    while(top[x]!=top[y])
    {
        if(dep[top[x]]<dep[top[y]]) swap(x,y);
        update(1,1,n,id[top[x]],id[x],k);
        x=fa[top[x]];
    }
    if(dep[x]>dep[y]) swap(x,y);
    update(1,1,n,id[x],id[y],k);
}

inline void query(int rt,int l,int r,int L,int R)
{
    if(L<=l && r<=R)
    {
        res+=sum[rt];
        res%=mo;
        return;
    }
    int mid=l+r>>1;
    pushdown(rt,mid-l+1,r-mid);
    if(L<=mid) query(rt<<1,l,mid,L,R);
    if(R>mid) query(rt<<1|1,mid+1,r,L,R);
    sum[rt]=(sum[rt<<1]+sum[rt<<1|1])%mo;
}

inline int addup(int x,int y)
{
    int ans=0;
    while(top[x]!=top[y])
    {
        if(dep[top[x]]<dep[top[y]]) swap(x,y);
        res=0;
        query(1,1,n,id[top[x]],id[x]);
        ans+=res; ans%=mo;
        x=fa[top[x]];
    }
    if(dep[x]>dep[y]) swap(x,y);
    res=0;
    query(1,1,n,id[x],id[y]);
    ans+=res;
    return ans%=mo;
}

inline void changeS(int x,int k)
{
    update(1,1,n,id[x],id[x]+siz[x]-1,k);
}

inline int addupS(int x)
{
    res=0;
    query(1,1,n,id[x],id[x]+siz[x]-1);
    return res;
}

int main()
{
    cin>>n>>m>>number>>mo;
    for(int i=1;i<=n;i++) scanf("%d",&w[i]);
    for(int i=1;i<=n-1;i++)
    {
        int aa,bb;
        scanf("%d%d",&aa,&bb);
        add(aa,bb); add(bb,aa);
    }
    dfs1(number,0,1);
    dfs2(number,number);
    build(1,1,n);
    while(m--)
    {
        int k,x,y,z;
        scanf("%d",&k);

        if(k==1)
        {
            scanf("%d%d%d",&x,&y,&z);
            change(x,y,z);
        }
        if(k==2)
        {
            scanf("%d%d",&x,&y);
            printf("%d\n",addup(x,y));
        }
        if(k==3)
        {
            scanf("%d%d",&x,&y);
            changeS(x,y);
        }
        if(k==4)
        {
            scanf("%d",&x);
            printf("%d\n",addupS(x));
        }
    }
}
树链剖分

2.SA

#include<iostream>
#include<cstdio>
#include<cstring>
#define maxn 1000010
using namespace std;
int num[maxn],sa[maxn],se[maxn],rk[maxn],n,m,height[maxn];
char ch[maxn];

void debug()
{
    printf("*****************\n");
    printf("下标");for(int i=1;i<=n;i++) printf("%d ",i);printf("\n");
    printf("sa  ");for(int i=1;i<=n;i++) printf("%d ",sa[i]);printf("\n");
    printf("rk ");for(int i=1;i<=n;i++) printf("%d ",rk[i]);printf("\n");
    printf("se  ");for(int i=1;i<=n;i++) printf("%d ",se[i]);printf("\n");
}

inline void rsort()
{
    for(int i=0;i<=m;i++) num[i]=0;
    for(int i=1;i<=n;i++) num[rk[i]]++;
    for(int i=1;i<=m;i++) num[i]+=num[i-1];
    for(int i=n;i>=1;i--) sa[ num[ rk[ se[i]]]--]=se[i];
}

inline void SA()
{
    rsort();
    for(int k=1,tot=1; tot<n; m=tot,k<<=1)
    {
        tot=0;
        for(int i=1;i<=k;i++) se[++tot]=n-k+i;
        for(int i=1;i<=n;i++) if(sa[i]>k) se[++tot]=sa[i]-k;
        rsort();
        swap(rk,se);
        rk[sa[1]]=tot=1;
        for(int i=2;i<=n;i++)
            if(se[sa[i-1]]==se[sa[i]] && se[sa[i]+k]==se[sa[i-1]+k])
                rk[sa[i]]=tot;
            else rk[sa[i]]=++tot;
    }
    for(int i=1;i<=n;i++) printf("%d ",sa[i]);
}

inline void HEIGHT()
{
    int k=0;
    for(int i=1;i<=n;i++) rk[sa[i]]=i;
    for(int i=1,j;i<=n;i++)
    {
        if(rk[i]==1) continue;
        if(k) --k;
        j=sa[rk[i]-1];
        while(j+k<=n && i+k<=n && ch[i+k]==ch[j+k]) k++;
        height[rk[i]]=k;
    }
    for(int i=1;i<=n;i++) printf("%d ",height[i]);
}

int main()
{
    cin>>ch;
    n=strlen(ch); m=127;
    for(int i=0;i<=n-1;i++)
    {
        rk[i+1]=ch[i]-48;
        se[i+1]=i+1;
    }
    SA();
//    HEIGHT();
    return 0;
}
后缀数组

3.KMP

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
char s[1000001],t[1000001];
int m,n,next[1000001];
int main()
{
    scanf("%s",s);
    n=strlen(s);
    scanf("%s",t);
    m=strlen(t);

    next[0]=-1;
    int k=-1;
    for(int i=1;i<m;i++)
    {
        while(k>=0 && t[i]!=t[k+1]) k=next[k];
        if(t[i]==t[k+1]) k++;
        next[i]=k;
    }

    int kk=-1; int ans=0;
    for(int i=0;i<n;i++)
    {
        while(kk>=0 && s[i]!=t[kk+1]) kk=next[kk];
        if(s[i]==t[kk+1]) kk++;
        if(kk==m-1) { cout<<i+1-m+1<<endl;kk=next[kk]; }
    }
    for(int i=0;i<=m-1;i++)
        cout<<next[i]+1<<" ";
    return 0;
}
KMP

4.treap

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;

struct asd{
    int ls,rs; //左右儿子
    int size; // 统计包含自身的节点个数
    int cnt; // 统计自己出现的次数 
    int dep; // 随机出来的优先级
    int val; // 自身的值 
} tree[10000001];
int root,size,n,ans;

void update(int k) // 更新节点的个数
{
    tree[k].size=tree[tree[k].ls].size+tree[tree[k].rs].size+tree[k].cnt;
    return; // 记住上面的式子加上自身的重复 
}

void left(int &k) // 将其的右儿子左转 
{
    int rson=tree[k].rs;
    tree[k].rs=tree[rson].ls; // 将自己的右儿子变为其右儿子的左儿子
    tree[rson].ls=k; // 把自己变为其右儿子的左儿子
    tree[rson].size=tree[k].size; // 然后在统计子树大小
    update(k); // 并且更新其节点
    k=rson; // 这个是将k的父亲把k这个儿子改成了rson 
}

/*
解释一下这个k到底是什么
其实这个k相当于一个地址,它所储存了一堆信息,然后我们修改了这个指针所对应的值
但没有改变这个指针里面的值,只是修改了指针让它指向了另外一个点。指向了另个位置所对应的值
*/

void right(int &k)
{
    int lson=tree[k].ls;
    tree[k].ls=tree[lson].rs;
    tree[lson].rs=k;
    tree[lson].size=tree[k].size;
    update(k);
    k=lson;
} // 与left同理 

void insert(int &k,int x)
{
    if(k==0) // 已经递归到了叶子节点
    {
        size++; // 总的节点数+1
        k=size; tree[k].size=1; tree[k].cnt=1;
        tree[k].val=x; tree[k].dep=rand(); // 随机一个堆:小根堆 
        return; 
    }
    tree[k].size++; // 如果没到叶节点,说明此节点可包含所插入的数 
    if(tree[k].val==x) { tree[k].cnt++; return; } // 如果相等直接加上重复 
    if(tree[k].val<x) // 如果小于放到右子树上 
    {
        insert(tree[k].rs,x); // 插入右子树
        if(tree[tree[k].rs].dep<tree[k].dep) // 违反了堆的性质
            left(k); // 将k的rson转到k上去,把k转下来 
    }
    if(tree[k].val>x) // 放到左子树
    {
        insert(tree[k].ls,x);
        if(tree[tree[k].ls].dep<tree[k].dep)
            right(k);
    }
}

void delet(int &k,int x) // 删除值等于x这个节点
{
    if(tree[k].val==x) // 找到了这个节点
    {
        if(tree[k].cnt>1) // 如果有重复的话就直接操作
        { tree[k].cnt--; tree[k].size--; return; }
        if(tree[k].ls*tree[k].rs==0) // 如果他没有重复且左右子树至少有一个0
            k=tree[k].ls+tree[k].rs;
        else if(tree[tree[k].ls].dep<tree[tree[k].rs].dep) // 两个子树都有,找到优先级最大然后转上去
             { right(k); delet(k,x); } // 此时的k已经变为叶子节点就可以直接删去
             else { left(k); delet(k,x); }
    }
    else
    {
        if(tree[k].val>x) { tree[k].size--; delet(tree[k].ls,x); }
        else { tree[k].size--; delet(tree[k].rs,x); } // 一直找下去直到k为叶子节点然后删除 
    }
}

int check1(int &k,int x)
{
    if(k==0) return 0;
    if(tree[k].val==x) return tree[tree[k].ls].size+1; // 如果找到了那么就是其左子树的个数+1
    if(tree[k].val<x) return tree[tree[k].ls].size+tree[k].cnt+check1(tree[k].rs,x);
    if(tree[k].val>x) return check1(tree[k].ls,x);
}

int check2(int &k,int x) // 寻找排名为x的值
{
    if(x<=tree[tree[k].ls].size) return check2(tree[k].ls,x);
    // 如果排名小于当前节点左子树的大小,就在他的左子树中找 
    if(x>tree[tree[k].ls].size+tree[k].cnt) return check2(tree[k].rs,x-tree[tree[k].ls].size-tree[k].cnt);
    // 如果排名大于当前节点左子树+他的重复的大小,就在他的右子树中找
    return tree[k].val; 
}

void min_max(int k,int x) // 找比x小的最大数
{
    if(k==0) return; // 如果找到没有
    if(tree[k].val<x) // 如果比此节点大
    { ans=k; min_max(tree[k].rs,x); } // 先赋值,然后再去找更优解 
    else min_max(tree[k].ls,x); // 如果小了就只能在其左子树中找 
}

void max_min(int k,int x) // 找比x大的最小值
{
    if(k==0) return;
    if(tree[k].val>x) { ans=k; max_min(tree[k].ls,x); }
    else max_min(tree[k].rs,x);
} 

int main()
{
    cin>>n; int number,x;
    for(int i=1;i<=n;i++)
    {
        scanf("%d%d",&number,&x);
        if(number==1) insert(root,x);
        if(number==2) delet(root,x);
        if(number==3) printf("%d\n",check1(root,x));
        if(number==4) printf("%d\n",check2(root,x));
        if(number==5) { min_max(root,x); printf("%d\n",tree[ans].val); }
        if(number==6) { max_min(root,x); printf("%d\n",tree[ans].val); }
    }
    return 0;
}
treap

5.splay(大常数平衡树)

#include<iostream>
#include<cstdio>
using namespace std;
int root,cnt,n,ans;

struct asd{
    int s[2];
    int fa;
    int key;
    int cnt;
    int pos;
    int size;
} tree[2000001];

inline void clear(int x) { tree[x].s[0]=tree[x].s[1]=tree[x].fa=tree[x].cnt=tree[x].key=tree[x].size=0; }
// 将当前点的各项值都清0 (用于删除之后)

inline int get(int x) { return tree[tree[x].fa].s[1]==x; }
// 判断当前点是他父节点的左儿子还是右儿子
 
inline void pushup(int x)
{
    if(x)
    {
        tree[x].size=tree[x].cnt;
        if(tree[x].s[0]) tree[x].size+=tree[tree[x].s[0]].size;
        if(tree[x].s[1]) tree[x].size+=tree[tree[x].s[1]].size;
    }
}
// 更新当前点的size值 (用于发生修改之后)

inline void rotate(int x)
{
    int old=tree[x].fa,oldf=tree[old].fa,which=get(x);
    tree[old].s[which]=tree[x].s[which^1];
    if(tree[old].s[which]) tree[tree[old].s[which]].fa=old;
    tree[x].s[which^1]=old;
    tree[old].fa=x;
    tree[x].fa=oldf;
    if(oldf) tree[oldf].s[tree[oldf].s[1]==old]=x;
    pushup(old); pushup(x);
}
// 一共包含三个步骤。。。真●恶心 
// step1:找出要变动节点(D)的父亲结点(B)以及父亲的父亲(A)并记录。。。判断D是B的左结点还是右结点
// step2:转换节点保证二叉树的大小关系不变。。。笼统概括(雾 ↓
/* 
我们已经判断了D是B的左儿子还是右儿子,设这个关系为K;
将D与K关系相反的儿子的父亲记为B与K关系相同的儿子(这里即为D的右儿子的父亲记为B的左儿子)
将D与K关系相反的儿子的父亲即为B(这里即为把G的父亲记为B)
将B的父亲即为D
将D与K关系相反的儿子记为B(这里即为把D的右儿子记为B)
将D的父亲记为A。
最后要判断,如果A存在(即rotate到的位置不是根的话),要把A的儿子记为D。
显而易见,rotate之后所有牵涉到变化的父子关系都要改变。
以上的树需要改变四对父子关系,BG DG BD AB,需要三个操作(BG BD AB)。
*/
// step3:pushup一下当前点和各个父结点的各个值

inline void splay(int x)
{
    for(int fa;fa=tree[x].fa;rotate(x))
        if(tree[fa].fa)
            rotate(get(x)==get(fa) ? fa:x);
    root=x;
}
// 实际上splay只是rotate的发展。。。就是不停的rotate。。。
// 因为没有确切的停止状态。。。此处代码直接到根
// 当然splay也会遇到一些特殊的情况。。。
// 如果是三点一条链的情况就需要先rotate x的父亲
// 不这样做会形成单旋使平衡树失衡。。。 
/*
inline void splay(int x,int tar)
{
    for(int fa;(fa=tree[x].fa!=tar;rotate(x))
        if(tree[fa]!=tar)
            rotate(get(x)==get(fa) ? fa:x);
    if(!tar) root=x;
}
*/

inline void insert(int x)
{
    if(root==0)
    {
        root=++cnt;
        tree[root].s[0]=0; tree[root].s[1]=0; tree[root].fa=0;
        tree[root].key=x; tree[root].cnt=1; tree[root].size=1;
        return;
    }
    int now=root,fa=0;
    while(1)
    {
        if(tree[now].key==x)
        {
            tree[now].cnt++;
            pushup(now); pushup(fa);
            splay(now); break;
        }
        fa=now; now=tree[now].s[tree[now].key<x];
        if(now==0)
        {
            int k=++cnt;
            tree[k].s[0]=tree[k].s[1]=0;
            tree[k].key=x;
            tree[k].size=1;
            tree[k].cnt=1;
            tree[k].fa=fa;
            tree[fa].s[tree[fa].key<x]=k;
            pushup(fa); splay(k);
            break;
        }
    }
}
// 如果k==0 即树为空,做一些处理直接返回。。。
//  如果遇到一个结点的关键字等于当前要插入的点的话
// 我们就等于把这个结点加了一个权值
// 因为在二叉搜索树中是不可能出现两个相同的点
// 并且要将当前点和它父亲结点的各项值更新一下。做一下splay。
// 如果已经到了最底下了,那么就可以直接插入
// 整个树的大小要+1,新结点的左儿子右儿子(虽然是空)父亲还有各项值要一一对应
// 并且最后要做一下他父亲的update(做他自己的没有必要)。做一下splay

inline int pre() { int x=tree[root].s[0]; while(tree[x].s[1]) x=tree[x].s[1]; return x; }

inline int nxe() { int x=tree[root].s[1]; while(tree[x].s[0]) x=tree[x].s[0]; return x; }

inline int find(int x) // 查询x的排名 
{
    int k=root;ans=0;
    while(1)
    {
        if(x<tree[k].key) k=tree[k].s[0];
        else
        {
            ans+=(tree[k].s[0] ? tree[tree[k].s[0]].size : 0);
            if(tree[k].key==x) { splay(k); return ans+1; }
            ans+=tree[k].cnt;
            k=tree[k].s[1];
        }
    }
}
// 

inline int findx(int x) // 查询排名为x的点 
{
    int k=root;
    while(1)
    {
        if(x<=tree[tree[k].s[0]].size && tree[k].s[0]) k=tree[k].s[0];
        else
        {
            x-=tree[tree[k].s[0]].size+tree[k].cnt;
            x=max(x,0);
            if(!x) return tree[k].key;
            k=tree[k].s[1];
        }
    }
}
//

inline void delet(int x)
{
    int hhh=find(x);
    if(tree[root].cnt>1) { tree[root].cnt--; return; }
    if(!tree[root].s[0] && !tree[root].s[1]) {clear(root); root=0; return; }
    if(!tree[root].s[0]) { int oldf=root; root=tree[root].s[1]; tree[root].fa=0; clear(oldf); return; }
    else
    if(!tree[root].s[1]) { int oldf=root; root=tree[root].s[0]; tree[root].fa=0; clear(oldf); return; }
    int leftbig=pre(),oldf=root;
    splay(leftbig);
    tree[tree[oldf].s[1]].fa=root;
    tree[root].s[1]=tree[oldf].s[1];
    clear(oldf); pushup(root); return;
}

int main()
{
    cin>>n;
    int opt,x;
    for(int i=1;i<=n;i++)
    {

        scanf("%d%d",&opt,&x);
        if(opt==1) insert(x);
        if(opt==2) delet(x);
        if(opt==3) printf("%d\n",find(x));
        if(opt==4) printf("%d\n",findx(x));
        if(opt==5) { insert(x); printf("%d\n",tree[pre()].key); delet(x); }
        if(opt==6) { insert(x); printf("%d\n",tree[nxe()].key); delet(x); }
    }
}
splay(大常数平衡树)

6.splay(区间翻转)

#include<iostream>
#include<cstdio>
#define INF 99999999
#define maxn 1000001
using namespace std;

int cnt,w[maxn],root,n,m,sz;
bool mark[maxn];

struct asd{
    int s[2];
    int key;
    int fa;
    int size;
} tree[maxn<<1];

inline void pushup(int x) { tree[x].size=tree[tree[x].s[0]].size+tree[tree[x].s[1]].size+1; }
inline void swap(int &x,int &y) { int t=x; x=y; y=t; }
inline bool get(int x) { return tree[tree[x].fa].s[1]==x; }

inline void pushdown(int x)
{
    if(x && mark[x])
    {
        mark[tree[x].s[0]]^=1;
        mark[tree[x].s[1]]^=1;
        swap(tree[x].s[0],tree[x].s[1]); // ???
        mark[x]=0;
    }
}

inline int build(int fa,int l,int r)
{
    if(l>r) return 0;
    int mid=l+r>>1;
    int now=++sz;
    tree[now].key=w[mid];
    tree[now].fa=fa;
    mark[now]=0;
    tree[now].s[0]=build(now,l,mid-1);
    tree[now].s[1]=build(now,mid+1,r);
    pushup(now);
    return now;
}

inline void rotate(int x)
{
    int old=tree[x].fa , oldf=tree[old].fa , which=get(x);
    pushdown(old); pushdown(x);
    tree[old].s[which] = tree[x].s[which^1];
    if (tree[old].s[which]) tree[tree[old].s[which]].fa = old;
    tree[old].fa=x;
    tree[x].fa=oldf;
    tree[x].s[which^1]=old;
    if(oldf) tree[oldf].s[tree[oldf].s[1]==old] = x;
    pushup(old); pushup(x);
}

inline void splay(int x,int tar)
{
    for(int fa;(fa=tree[x].fa)!=tar;rotate(x))
        if(tree[fa].fa!=tar)
            rotate(get(fa)==get(x) ? fa:x);
    if(!tar) root=x;
}

inline int findx(int k,int x)
{
    while(1)
    {
        pushdown(k);
        if(x<=tree[tree[k].s[0]].size) k=tree[k].s[0];
        else
        {
            x-=tree[tree[k].s[0]].size+1;
            if(!x) return k;
            k=tree[k].s[1];
        }
    }
}

/*
int findx(int k,int x)
{
    while(1)
    {
        pushdown(k);
        if(x<=tree[tree[k].s[0]].size) k=tree[k].s[0];
        else
        {
            x-=tree[tree[k].s[0]].size;
            if(x==1)
            {
//                splay(k,0); // 加不加好像都行。。。但是这个可以维护树高 
                return k;
            }
            k=tree[k].s[1];
            --x;
        }
    }
}
*/

inline void print(int x)
{
    pushdown(x);
    if(tree[x].s[0]) print(tree[x].s[0]);
    if(tree[x].key!=-INF && tree[x].key!=INF) printf("%d ",tree[x].key);
    if(tree[x].s[1]) print(tree[x].s[1]);
}

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) w[i+1]=i;
    w[1]=-INF; w[n+2]=INF;
    root=build(0,1,n+2);
    int x,y;
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&x,&y);
        int x1=findx(root,x);
        int y1=findx(root,y+2);
        splay(x1,0);
        splay(y1,x1);
        mark[tree[tree[root].s[1]].s[0]]^=1;
    }
    print(root);
}

// 假如我们要在Splay中修改区间的话,可以先查找siz值为l与r+2的两个节点
// 将一个旋转到根,另一个旋转到根的左儿子上
// 则要修改的区间就是根的右孩子的左子树,直接打标记即可
splay区间翻转

 7.ST标

#include<iostream>
#include<cmath>
#include<cstdio>
using namespace std;
int n,q,a[100001],L,R,f1[100001][21];
inline void ST()
{
    int k=log(n)/log(2);
//  每次并不是增加一个长度,而是使用倍增的思想,每次增加2^i个长度。
    for(register int i=1;i<=n;i++) f1[i][0]=a[i];
    for(register int j=1;j<=k;j++)
        for(register int i=1;i+(1<<j)-1<=n;i++)
        {
            f1[i][j]=max(f1[i][j-1],f1[i+(1<<(j-1))][j-1]);
        }
}
inline int RMQ(int L,int R)
{
    int k=log(R-L+1)/log(2);
    return max(f1[L][k],f1[R-(1<<k)+1][k]);
}
int main()
{
    scanf("%d%d",&n,&q);
    for(register int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    ST();
    for(register int i=1;i<=q;i++)
    {
        scanf("%d%d",&L,&R);
        printf("%d\n",RMQ(L,R));
    }
}
ST表

 

posted on 2018-04-01 10:21  zzzyc  阅读(198)  评论(0编辑  收藏  举报