zoukankan      html  css  js  c++  java
  • 被论文洗脑(徐明宽<<非常规大小分块算法初探>>)

    今天闲来无事,无题可做(因为太菜了开的题都不会做)

    于是打开了2017IOI国家候选队的论文,徐明宽的<<非常规大小分块算法初探>>

    http://www.noi.cn/noi-news/noi/786-ctsc2017

    然后略过了前面一些看不太懂的东西.

    看到了method of four russians这个lca算法

    预处理O(n),查询O(1),还是在线的

    看起来很牛逼,于是就仔细理解了一下

    又上网找了找资料,结果发现网上没什么资料

    于是就根据论文自己打了一打.

    然后就不好了,打了一个下午.

    原文对做法讲的已经十分清楚了

    首先dfs,处理出dfs序(一个点出现多次的那种)

    然后转化为正负1RMQ问题(因为相邻两点深度差最多为1)

    然后正负1RMQ问题可以分块解决

    块之间用普通RMQ倍增法维护

    一个块内直接用一种难以描述的方法维护

    具体来说是这样

    设一个块内有s个元素,分别为a[0]-a[s-1]

    先差分,b[i]=a[i+1]-a[i]

    i属于[0,s-2]

    然后所有的块就可被归为2^(s-1)类,因为b[i]不是-1,就是1(0?不存在的,一条边两边点的深度不可能相等)

    每一类处理出在一定范围内最小值的位置

    然后就好了

    查询时乱搞一波

    具体来说就是包含块算块,注意边界,无块就用维护块内信息的数组回答.

    (话说这方法考试时真能打吗?直接被续光时间)

    至于这个算法的常数,详见论文.

    例题

    洛谷P3379 【模板】最近公共祖先(LCA)

    上代码

    //method of four russians
    //prework O(n) ask O(1)
    #include<bits/stdc++.h>
    using namespace std;
    const int N=500010,M=500010,KK=250010,P=19,S_2=256,S=9;
    int b[N<<1],ne[N<<1],fi[N],k,n,m,root,s;
    inline void read(int &x){
        x=0;  char ch=getchar();
        while(ch<'0'||ch>'9') ch=getchar();
        while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    }
    void add(int x,int y){
        b[++k]=y; ne[k]=fi[x]; fi[x]=k;
        b[++k]=x; ne[k]=fi[y]; fi[y]=k; 
    }
    void in(){
        read(n); read(m); read(root);
        for (int i=1; i<n; ++i){
            int x,y; read(x); read(y);
            add(x,y);
        }
        s=log2(n)/2;
        if (!s) s=1;
    //    cerr<<"in"<<s<<endl;
    }
    int a[(N<<1)+10],deep[N],la[N],len;
    void dfs(int x){
        la[x]=len; a[len++]=x; 
        for (int j=fi[x]; j; j=ne[j])
        if (!deep[b[j]]){
            deep[b[j]]=deep[x]+1;
            dfs(b[j]);
            la[x]=len; a[len++]=x;
        }
    }
    int f[P][KK],lg[KK],minn[S_2][S][S],dep[S],re[KK];
    void prework(){
        deep[0]=INT_MAX; deep[root]=1; dfs(root);    
    //    for (int i=0; i<len; i++) cerr<<a[i]<<" "; puts("");
    //    for (int i=0; i<len; i++) cerr<<deep[a[i]]<<" "; puts("");
        /*-----------------------------------------------------*/    
        //S numbers,s-1 interval,less than 2^(s-1) 
        for (int i=0; i<(1<<(s-1)); i++)
            for (int j=0; j<s; j++){//from 0
                minn[i][j][j]=j; dep[j]=0;
                for (int k=j+1; k<s; k++){
                    if ((i>>(k-1))&1) dep[k]=dep[k-1]+1; else dep[k]=dep[k-1]-1;
                    if (dep[k]<=dep[minn[i][j][k-1]]) minn[i][j][k]=k; else minn[i][j][k]=minn[i][j][k-1];
    //                cerr<<i<<" "<<j<<" "<<k<<" "<<dep[k]<<" "<<minn[i][j][k]<<endl; system("pause");
                }
            }
        for (int i=0; i<=(len-1)/s; i++){
            int l=i*s,t=0;
            for (int j=0; j<s-1; j++) if (deep[a[l+1+j]]-deep[a[l+j]]!=-1) t|=1<<j;
            re[i]=t;
    //        cerr<<i<<" "<<re[i]<<endl;
        }
        /*----------------------------------------------------*/
        int kk=(len-1)/s,p=(int)log2(kk+1)+1;
        lg[1]=0; for (int i=2; i<=kk; i++) lg[i]=lg[i>>1]+1;
        /*----------------------------------------------------*/
        for (int i=0; i<len; i++) if (deep[f[0][i/s]]>deep[a[i]]) f[0][i/s]=a[i];
        for (int j=1; j<=p; j++)
        for (int i=0; i<=kk; i++)
        if (i+(1<<(j-1))<=kk){
            int u=f[j-1][i],v=f[j-1][i+(1<<(j-1))];
            if (deep[u]<deep[v]) f[j][i]=u; else f[j][i]=v;
        }else break;
        /*-----------------------------------------------------*/
    }
    int ask(int l,int r){
        if (l>r) l^=r^=l^=r;
        int sl=l/s,sr=r/s,ll=l-sl*s,rr=r-sr*s;
        if (sl!=sr){
            int res=0,u,v;
            if (sl+1<=sr-1){
                int j=lg[sr-sl-1];
                u=f[j][sl+1]; v=f[j][sr-(1<<j)];//from sl+1 to sr-1
                if (deep[u]<deep[v]) res=u; else res=v;
            }
            u=a[r-rr+minn[re[sr]][0][rr]];
            if (deep[u]<deep[res]) res=u;
            v=a[l-ll+minn[re[sl]][ll][s-1]];
            if (deep[v]<deep[res]) res=v;
            return res;
        }
        else return a[l-ll+minn[re[sl]][ll][rr]];
    }
    void ans_the(){
        while (m--){
            int x,y; scanf("%d%d",&x,&y);
            printf("%d
    ",ask(la[x],la[y]));
        }
    }
    int main(){
        in();
        prework();
        ans_the();
    }
  • 相关阅读:
    词法分析程序
    大数据概述作业
    编译原理心得
    简化C语言文法
    解决:eclipse引入一个新项目所有jsp报错
    解决: 启动tomcat java.net.BindException: Address already in use: JVM_Bind错误
    myeclipse优化
    jquery冲突
    QQ上传大文件为什么这么快
    java中的重写和重载
  • 原文地址:https://www.cnblogs.com/Yuhuger/p/8435900.html
Copyright © 2011-2022 走看看