zoukankan      html  css  js  c++  java
  • CF1142B Lynyrd Skynyrd

    Link
    有两种做法:
    第一种是(O(nlog n))的。
    我们预处理两个数组:
    (pre_i)表示(p)(i)前面的那个数是(pre_i)
    (lst_i)表示(a)(a_i)前一个(pre_{a_i})的位置。(代码中是(f_0)
    那么每个数往前跳几次(lst),也就会对应排列(p)中的一段连续子串。
    然后处理往前跳(lst)的倍增数组。
    我们知道,(p)是一个循环排列,所以对于每个数,以这个数结束的最短的是(p)的循环移位的(a)的子序列,就是从这个数往前跳(n-1)(lst)得到的子序列。
    所以我们处理出每个点往前跳(n-1)(lst)得到的位置(edp)
    对于一次询问(l,r),如果(l,r)中存在子序列为(p)的循环移位,那么就会满足(exist iin[l,r],edp_iin[l,r])
    所以我们用(st)表维护区间最小值即可。

    #include<bits/stdc++.h>
    using namespace std;
    const int N=200007;
    int p[N],a[N],f[21][N],pre[N],lst[N],Log[N],st[21][N];
    int max(int a,int b){return a>b? a:b;}
    int read(){int x;scanf("%d",&x);return x;}
    int get(int l,int r){int k=Log[r-l+1];return max(st[k][l],st[k][r-(1<<k)+1]);}
    int main()
    {
    	int n=read(),m=read(),q=read(),i,j,l,r;
    	for(i=1;i<=n;++i) p[i]=read();
    	p[0]=p[n];
    	for(i=1;i<=n;++i) pre[p[i]]=p[i-1];
    	for(i=1;i<=m;++i) a[i]=read();
    	for(i=1;i<=m;++i) f[0][i]=lst[pre[a[i]]],lst[a[i]]=i;
    	for(i=2;i<=n||i<=m;++i) Log[i]=Log[i>>1]+1;
    	for(i=1;i<=Log[n];++i) for(j=1;j<=m;++j) f[i][j]=f[i-1][f[i-1][j]];
    	for(i=1;i<=m;++i) for(st[j=0][i]=i;j<=Log[n-1];++j) if((n-1)&(1<<j)) st[0][i]=f[j][st[0][i]];
    	for(i=1;i<=Log[m];++i) for(j=1;j+(1<<i)-1<=m;++j) st[i][j]=max(st[i-1][j],st[i-1][j+(1<<i-1)]);
    	while(q--) l=read(),r=read(),putchar(get(l,r)>=l? '1':'0');
    }
    

    第二种是(O(n))的。
    我们处理两个数组:
    (ppre_i)表示(p)(i)前面的那个数是(ppre_i)
    (apre_i)表示(a)中前一个(a_i)的位置。
    然后从前往后扫(a)数组,把(a_i)前面所有未连边的(ppre_{a_i})的位置向(i)连边,并且打上标记,下次不再连边。
    那么我们知道每个点最多只有一个入边。没有入边的,我们新建一个(0)到这个点的边。
    总的,我们会建出一棵树。
    (a)数组中(a_i)向前跳一次(lst)(上面那个做法的跳)也就是跳一次父亲。
    所以上面做法的跳(n-1)次就变成了(n-1)级祖先。
    考虑dfs的过程,dfs到某个点经过的点(也就是dfs的栈)存的都是根到当前节点的路径。
    所以每个节点dfs到时(进栈)把当前深度的节点((b)数组)记为自己,因此(n-1)级祖先就是(b[dep[u]-(n-1)])

    #include<bits/stdc++.h>
    #define pb push_back
    using namespace std;
    const int N=200007;
    int n,m,q,p[N],a[N],apre[N],lst[N],ppre[N],fa[N],dep[N],w[N],b[N];
    vector<int>G[N];
    int max(int a,int b){return a>b? a:b;}
    int min(int a,int b){return a<b? a:b;}
    int read(){int x;scanf("%d",&x);return x;}
    void dfs(int u)
    {
        int i,v;
        b[dep[u]]=u,w[u]=dep[u]>=n? b[dep[u]-(n-1)]:m+1;
        for(i=G[u].size()-1;~i;--i) v=G[u][i],dep[v]=dep[u]+1,dfs(v);
    }
    int main()
    {
        n=read(),m=read(),q=read();int i,j;
        for(i=1;i<=n;++i) p[i]=read();
        p[0]=p[n];
        for(i=1;i<=n;++i) ppre[p[i]]=p[i-1];
        for(i=1;i<=m;++i)
        {
    	a[i]=read(),apre[i]=lst[a[i]],lst[a[i]]=i;
    	for(j=lst[ppre[a[i]]];j&&!fa[j];j=apre[j]) fa[j]=i;
        }
        for(i=1;i<=m;++i) fa[i]? G[fa[i]].pb(i):G[0].pb(i);
        dfs(0);
        for(i=m-1;i;--i) w[i]=min(w[i+1],w[i]);
        while(q--) i=read(),j=read(),putchar(48+(w[i]<=j));
    }
    
  • 相关阅读:
    [TimLinux] CSS 纯CSS实现动画展开/收起功能
    [TimLinux] CSS pre超长自动换行
    j2ee之struts2表单细节处理
    j2ee之struts2的国际化数据方式
    j2ee之struts2拦截器()
    j2ee之struts2文件下载
    j2ee之struts2文件上传
    j2ee国际化数据方式
    j2ee监听器的实现及配置方法
    j2ee过滤器实现的主要代码
  • 原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/11527122.html
Copyright © 2011-2022 走看看