zoukankan      html  css  js  c++  java
  • GDKOI2015

    problems

    http://gdoi.sysu.edu.cn/wp-content/uploads/2015/03/GDKOI-2015-day1.pdf

    http://gdoi.sysu.edu.cn/wp-content/uploads/2015/03/GDKOI-2015-day21.pdf

    necklace

    回文串问题。

    把字符串复制一遍,使得环状变成线状。

    然后就是问最长回文串,直接套用manacher算法。

    wordcount

    网络流问题。

    把每个格点(i,j)在网络流中拆分成两个点,这两个点之间连一条流量为cnt[i][j]的边,其中左边的称为入点,右边的称为出点。

    GDKOI2015 - maijing3007 - maijing
    然后对于格点(i,j)和他相邻的某个格点(k,l)满足:mat[i][j]和mat[k][l]恰好为单词w的某相邻两位,那么从格点(i,j)的出点连一条边到格点(k,l)的入点,流量为正无穷大。
    最后如果格点(i,j)满足:mat[i][j]恰好为单词w的第一个字符,那么就从源点S连一条边到格点(i,j)的入点,流量为正无穷大;如果格点(i,j)满足:mat[i][j]恰好为单词w的最后一个字符,那么就从格点(i,j)的入点连一条边到汇点T,流量为正无穷大。
    circle
    欧拉回路问题。
    我们发现以下的性质:
    (Ⅰ)如果N为奇数那么无解。
          证明:
          假设N为奇数。
          考虑到达0前的点A,必定为下面两个方程的解的其中一个:
          2A%N=0
          (2A+1)%N=0
          容易知道第一个方程的解为0(舍去),第二个方程的解为N/2。所以A=N/2。
          考虑到达N-1前的点B,同理得B=N/2。
          因为A=B,不符合条件,所以N为奇数时无解。
          所以接下来讨论的都是N为偶数的情况。
    (Ⅱ)X(0<=X<=N/2-1)连向2X和2X+1;X+N/2连向2X和2X+1。
    (Ⅲ)有且仅有X和X+N/2连向2X;有且仅有X和X+N/2连向2X+1。
    总结上面如图所示:
    GDKOI2015 - maijing3007 - maijing
    我们发现每个点有另外一个点,满足他们的出边和入边完全相同。
    我们将这N/2对点合并,并删除重边,那么新图有N/2个点,N条边,并且每个点只有2条出边,2条入边。
    我们要恰好经过新图中每个点两次,这等价于恰好经过每条边一次。
    “恰好经过每条边一次”这恰好就是欧拉回路。
    要求字典序最大只需要在DFS时贪心一下即可。
    参考程序:
    #include<cstdio>
    #include<cstdlib>
    #include<iostream>
    #include<fstream>
    #include<algorithm>
    #include<cstring>
    #include<string>
    #include<cmath>
    #include<queue>
    #include<stack>
    #include<map>
    #include<utility>
    #include<set>
    #include<bitset>
    #include<vector>
    #include<functional>
    
    using namespace std;
    
    typedef long long LL;
    typedef double DB;
    typedef pair<int,int> PII;
    
    #define mmst(a,v) memset(a,v,sizeof(a))
    #define mmcy(a,b) memcpy(a,b,sizeof(a))
    #define re(i,a,b) for(i=a;i<=b;i++)
    #define red(i,a,b) for(i=a;i>=b;i--)
    #define fi first
    #define se second
    
    template<class T>inline T sqr(T x){return x*x;}
    template<class T>inline void upmin(T &t,T tmp){if(t>tmp)t=tmp;}
    template<class T>inline void upmax(T &t,T tmp){if(t<tmp)t=tmp;}
    
    const DB EPS=1e-9;
    inline int dblcmp(DB x){if(abs(x)<EPS)return 0;return(x>0)?1:-1;}
    
    inline void SetOpen(string s)
    {
    freopen((s+".in").c_str(),"r",stdin);
    freopen((s+".out").c_str(),"w",stdout);
    }
    
    inline int Getin_Int()
    {
    int res=0,flag=1;char z;
    for(z=getchar();z!=EOF && z!='-' && !isdigit(z);z=getchar());
    if(z==EOF)return 0;
    if(z=='-'){flag=-flag;z=getchar();}
    for(;z!=EOF && isdigit(z);res=res*10+z-'0',z=getchar());
    return res*flag;
    }
    inline LL Getin_LL()
    {
    LL res=0,flag=1;char z;
    for(z=getchar();z!=EOF && z!='-' && !isdigit(z);z=getchar());
    if(z==EOF)return 0;
    if(z=='-'){flag=-flag;z=getchar();}
    for(;z!=EOF && isdigit(z);res=res*10+z-'0',z=getchar());
    return res*flag;
    }
    
    const int maxN=10000;
    
    int N;
    vector<int> edge[maxN/2+100],ans;
    
    inline int DFS(int x)
    {
    int now=x;
    x%=N/2;
    while(!edge[x].empty())
    {
    int y=edge[x].back();
    edge[x].pop_back();
    DFS(y);
    }
    ans.push_back(now);
    }
    
    int main()
    {
    SetOpen("circle");
    int i;
    N=Getin_Int();
    if(N&1){puts("-1
    ");return 0;}
    re(i,0,N/2-1){edge[i].push_back(2*i);edge[i].push_back(2*i+1);}
    DFS(0);
    red(i,ans.size()-1,0)printf("%d ",ans[i]);printf("
    ");
    return 0;
    }
    View Code

    tree
    数据结构问题。
    首先使用DFS序,这样每棵子树在线段树中都是连续的区间,不妨设点u的子树在线段树中的区间为[l[u],r[u]]。
    建C棵线段树,第i棵线段树中记录当前节点到根节点的路径中颜色为i的点的权值和。
    对于3种不同的命令的做法:
    Change u x y:交换第x棵线段树和第y棵线段树中属于区间[l[u],r[u]]的若干个结点(因为要交换,所以线段树用,不过要注意的一点是,u的父亲到根节点的路径中,颜色为x的点的权值和 与 颜色为y的点的权值和 是不一样的,因此要加减 他们的差。

    Ask u v c:先求出lca,然后在第c棵中查询:u到根节点的路径中颜色为c的点的权值和+u到根节点的路径中颜色为c的点的权值和-lca到根节点的路径中颜色为c的权值和-lca的父亲到根节点的路径中颜色为c的权值和

    Set u c val:建设u原来的颜色是d,原来的权值为f,将第d棵线段树中属于区间[l[u],r[u]]的节点都减去f;然后在第c线段树中属于区间[l[u],r[u]]的结点都加上val。
    #include<cstdio>
    #include<cstdlib>
    #include<iostream>
    #include<fstream>
    #include<algorithm>
    #include<cstring>
    #include<string>
    #include<cmath>
    #include<queue>
    #include<stack>
    #include<map>
    #include<utility>
    #include<set>
    #include<bitset>
    #include<vector>
    #include<functional>
    
    using namespace std;
    
    typedef long long LL;
    typedef double DB;
    typedef pair<int,int> PII;
    
    #define mmst(a,v) memset(a,v,sizeof(a))
    #define mmcy(a,b) memcpy(a,b,sizeof(a))
    #define re(i,a,b) for(i=a;i<=b;i++)
    #define red(i,a,b) for(i=a;i>=b;i--)
    #define fi first
    #define se second
    
    template<class T>inline T sqr(T x){return x*x;}
    template<class T>inline void upmin(T &t,T tmp){if(t>tmp)t=tmp;}
    template<class T>inline void upmax(T &t,T tmp){if(t<tmp)t=tmp;}
    
    const DB EPS=1e-9;
    inline int dblcmp(DB x){if(abs(x)<EPS)return 0;return(x>0)?1:-1;}
    
    inline void SetOpen(string s)
    {
    freopen((s+".in").c_str(),"r",stdin);
    freopen((s+".out").c_str(),"w",stdout);
    }
    
    inline int Getin_Int()
    {
    int res=0,flag=1;char z;
    for(z=getchar();z!=EOF && z!='-' && !isdigit(z);z=getchar());
    if(z==EOF)return 0;
    if(z=='-'){flag=-flag;z=getchar();}
    for(;z!=EOF && isdigit(z);res=res*10+z-'0',z=getchar());
    return res*flag;
    }
    inline LL Getin_LL()
    {
    LL res=0,flag=1;char z;
    for(z=getchar();z!=EOF && z!='-' && !isdigit(z);z=getchar());
    if(z==EOF)return 0;
    if(z=='-'){flag=-flag;z=getchar();}
    for(;z!=EOF && isdigit(z);res=res*10+z-'0',z=getchar());
    return res*flag;
    }
    
    const int maxN=50000;
    const int maxM=50000;
    const int maxC=10;
    
    int N,M,C;
    int c[maxN+100],v[maxN+100];
    int first[maxN+100],now;
    struct Tedge{int v,next;}edge[2*maxN+100];
    int fa[maxN+100],dep[maxN+100];
    int jump[maxN+100][30];
    int sum[maxN+100][maxC+3];
    int id[maxN+100],l[maxN+100],r[maxN+100],cnt;
    
    inline void addedge(int u,int v)
    {
    now++;
    edge[now].v=v;
    edge[now].next=first[u];
    first[u]=now;
    }
    
    int que[maxN+100],head,tail;
    inline void BFS(int S)
    {
    mmst(fa,-1);
    que[head=tail=0]=S;
    fa[S]=0;
    dep[S]=1;
    while(head<=tail)
    {
    int u=que[head++],i,v;
    for(i=first[u],v=edge[i].v;i!=-1;i=edge[i].next,v=edge[i].v)if(v!=fa[u])
    {
    que[++tail]=v;
    fa[v]=u;
    dep[v]=dep[u]+1;
    }
    }
    }
    
    int sta[maxN+100],top;
    int last[maxN+100];
    inline void DFS(int S)
    {
    int j;
    re(j,1,N)last[j]=first[j];
    sta[top=1]=S;
    id[S]=cnt=1;
    while(top>=1)
    {
    int u=sta[top],&i=last[u],v;
    for(v=edge[i].v;i!=-1;i=edge[i].next,v=edge[i].v)if(!id[v])
    {
    id[v]=++cnt;
    sta[++top]=v;
    break;
    }
    if(i==-1)top--;
    }
    }
    
    inline void swim(int &x,int H)
    {
    int i;
    for(i=0;H!=0;H/=2,i++)if(H&1)x=jump[x][i];
    }
    inline int Ask_LCA(int x,int y)
    {
    if(dep[x]<dep[y])swap(x,y);
    swim(x,dep[x]-dep[y]);
    if(x==y)return x;
    int i;
    red(i,30-1,0)if(jump[x][i]!=jump[y][i]){x=jump[x][i];y=jump[y][i];}
    return jump[x][0];
    }
    
    struct Ttree
    {
    Ttree *l,*r;
    int add,v;
    }*tree[maxC+10];
    
    inline Ttree *NewTtree()
    {
    Ttree *res=new Ttree;
    res->l=res->r=0;
    res->add=res->v=0;
    return res;
    }
    
    inline void down(Ttree *&root,int l,int r,int mid)
    {
    if(root->add==0)return;
    int add=root->add;root->add=0;
    if(l==r)return;
    if(!root->l)root->l=NewTtree();
    if(l==mid) root->l->v+=add;
    root->l->add+=add;
    if(!root->r)root->r=NewTtree();
    if(mid+1==r) root->r->v+=add;
    root->r->add+=add;
    }
    
    inline void update(Ttree *&root,int l,int r,int x,int y,int v)
    {
    if(!root) root=NewTtree();
    if(l>r || y<l || r<x)return;
    int mid=(l+r)/2;
    down(root,l,r,mid);
    if(x<=l && r<=y)
    {
    if(l==r)root->v+=v;
    root->add+=v;
    return;
    }
    update(root->l,l,mid,x,y,v);
    update(root->r,mid+1,r,x,y,v);
    }
    
    inline void change(Ttree *&R1,Ttree *&R2,int l,int r,int x,int y,int temp1,int temp2)
    {
    if(!R1) R1=NewTtree();
    if(!R2) R2=NewTtree();
    if(l>r || y<l || r<x) return;
    int mid=(l+r)/2;
    down(R1,l,r,mid);
    down(R2,l,r,mid);
    if(x<=l && r<=y)
    {
    if(l==r)R1->v+=-temp1+temp2;R1->add+=-temp1+temp2;
    if(l==r)R2->v+=-temp2+temp1;R2->add+=-temp2+temp1;
    swap(R1,R2);
    return;
    }
    change(R1->l,R2->l,l,mid,x,y,temp1,temp2);
    change(R1->r,R2->r,mid+1,r,x,y,temp1,temp2);
    }
    
    inline int ask(Ttree *&root,int l,int r,int x)
    {
    if(!root) root=NewTtree();
    if(l>r || x<l || r<x)return 0;
    int mid=(l+r)/2;
    down(root,l,r,mid);
    if(x<=l && r<=x)return root->v;
    if(x<=mid) return ask(root->l,l,mid,x); else return ask(root->r,mid+1,r,x);
    }
    
    int main()
    {
    SetOpen("tree");
    int i,j;
    N=Getin_Int();C=0;
    re(i,1,N){c[i]=Getin_Int()+1;upmax(C,c[i]);}
    re(i,1,N)v[i]=Getin_Int();
    mmst(first,-1);now=-1;
    re(i,1,N-1)
    {
    int x=Getin_Int()+1,y=Getin_Int()+1;
    addedge(x,y);
    addedge(y,x);
    }
    BFS(1);
    re(i,0,tail)
    {
    int u=que[i];
    jump[u][0]=fa[u];
    re(j,1,30-1)jump[u][j]=jump[jump[u][j-1]][j-1];
    }
    re(i,0,tail)
    {
    int u=que[i];
    re(j,1,C)sum[u][j]=sum[fa[u]][j];
    sum[u][c[u]]+=v[u];
    }
    DFS(1);
    red(j,tail,0)
    {
    int u=que[j],v;
    l[u]=r[u]=id[u];
    for(i=first[u],v=edge[i].v;i!=-1;i=edge[i].next,v=edge[i].v)if(v!=fa[u])
    {
    upmin(l[u],l[v]);
    upmax(r[u],r[v]);
    }
    }
    re(i,1,N)re(j,1,C)update(tree[j],1,N,id[i],id[i],sum[i][j]);
    M=Getin_Int();
    while(M--)
    {
    char S[20];
    int a,b,x,y,c,val,lca,temp1,temp2,temp3;
    scanf("%s",S);
    switch(S[0])
    {
    case 'C':
    a=Getin_Int()+1;x=Getin_Int()+1;y=Getin_Int()+1;
    temp1=ask(tree[x],1,N,id[fa[a]]);
    temp2=ask(tree[y],1,N,id[fa[a]]);
    change(tree[x],tree[y],1,N,l[a],r[a],temp1,temp2);
    break;
    case 'A':
    a=Getin_Int()+1;b=Getin_Int()+1;c=Getin_Int()+1;
    lca=Ask_LCA(a,b);
    printf("%d
    ",ask(tree[c],1,N,id[a])+ask(tree[c],1,N,id[b])-ask(tree[c],1,N,id[lca])-ask(tree[c],1,N,id[fa[lca]]));
    break;
    case 'S':
    a=Getin_Int()+1;c=Getin_Int()+1;val=Getin_Int();
    re(i,1,C)
    {
    temp1=ask(tree[i],1,N,id[a])-ask(tree[i],1,N,id[fa[a]]);
    if(temp1==0) continue;
    update(tree[i],1,N,l[a],r[a],-temp1);
    break;
    }
    update(tree[c],1,N,l[a],r[a],val);
    break;
    }
    }
    return 0;
    }
    View Code
     
    watchdogs
    动态规划问题。
    将题目的模型简化得到:
     GDKOI2015 - maijing3007 - maijing
    上下各有N个点,之间有若干条连线。
    选择若干条不相交的直线,任意两条直线不能有公共点,每覆盖一个点都有一个分数(上面为vi,下面为pi),求最大的分数和。
    首先对于每条直线按a从小到大排序。
    枚举直线:
    GDKOI2015 - maijing3007 - maijing
    我们发现,如果选择了这条直线,那么a前面的那些点只能连向b前面的点。 
    记F[i]表示当前连向的点的最大编号为i时的最大的权值和,注意F是可以随着枚举而不断更新的。
    就是说询问F[1..b-1]的最大值。
    用树状数组。
    然后可以更新F[b].
     
    planetcup
    枚举进入第一轮比赛的第K名的分数(假设是x)。
    容易知道对于0国分数小于x的选手,参加第一轮比赛;对于1国分数小于x的选手,参加第二轮比赛。
    所以参加第一轮比赛的选手中,分数小于x的选手都是0国的。
    先把0国分数小于x的选手筛出去,他们没有贡献。
    剩下的为1国选手和分数大于等于x的0国选手。
    将他们按第二轮比赛的成绩从小到大排序。
    记F[i][j]表示前i个人,有j个人参加了第一轮比赛且在前K名,容易知道参加的第二轮比赛的人有i-j个。
    转移方程容易得到。
    参考程序:
    #include<cstdio>
    #include<cstdlib>
    #include<iostream>
    #include<fstream>
    #include<algorithm>
    #include<cstring>
    #include<string>
    #include<cmath>
    #include<queue>
    #include<stack>
    #include<map>
    #include<utility>
    #include<set>
    #include<bitset>
    #include<vector>
    #include<functional>
    
    using namespace std;
    
    typedef long long LL;
    typedef double DB;
    typedef pair<int,int> PII;
    
    #define mmst(a,v) memset(a,v,sizeof(a))
    #define mmcy(a,b) memcpy(a,b,sizeof(a))
    #define re(i,a,b) for(i=a;i<=b;i++)
    #define red(i,a,b) for(i=a;i>=b;i--)
    #define fi first
    #define se second
    
    template<class T>inline T sqr(T x){return x*x;}
    template<class T>inline void upmin(T &t,T tmp){if(t>tmp)t=tmp;}
    template<class T>inline void upmax(T &t,T tmp){if(t<tmp)t=tmp;}
    
    const DB EPS=1e-9;
    inline int dblcmp(DB x){if(abs(x)<EPS)return 0;return(x>0)?1:-1;}
    
    inline void SetOpen(string s)
    {
    freopen((s+".in").c_str(),"r",stdin);
    freopen((s+".out").c_str(),"w",stdout);
    }
    
    inline int Getin_Int()
    {
    int res=0,flag=1;char z;
    for(z=getchar();z!=EOF && z!='-' && !isdigit(z);z=getchar());
    if(z==EOF)return 0;
    if(z=='-'){flag=-flag;z=getchar();}
    for(;z!=EOF && isdigit(z);res=res*10+z-'0',z=getchar());
    return res*flag;
    }
    inline LL Getin_LL()
    {
    LL res=0,flag=1;char z;
    for(z=getchar();z!=EOF && z!='-' && !isdigit(z);z=getchar());
    if(z==EOF)return 0;
    if(z=='-'){flag=-flag;z=getchar();}
    for(;z!=EOF && isdigit(z);res=res*10+z-'0',z=getchar());
    return res*flag;
    }
    
    const int maxN=200;
    const int maxK=maxN/2;
    
    int N,K;
    struct Tdata
    {
    int x,y,z;
    inline void input(){x=Getin_Int();y=Getin_Int();z=Getin_Int();}
    }data[maxN+10];
    int F[maxN+10][maxK+10];
    int ans;
    
    inline bool cmpy(Tdata a,Tdata b){return a.y>b.y;}
    
    int main()
    {
    SetOpen("planetcup");
    int i,j,k;
    N=Getin_Int();K=Getin_Int();
    re(i,1,N)data[i].input();
    sort(data+1,data+N+1,cmpy);
    ans=0;
    re(k,1,N)
    {
    int p=data[k].x,cnt=0;
    mmst(F,-1);
    F[0][0]=0;
    re(i,0,N-1)
    {
    if(data[i+1].z==0 && data[i+1].x<p)
    {
    re(j,0,K)F[i+1][j]=F[i][j];
    continue;
    }
    re(j,0,K)
    {
    if(F[i][j]==-1)continue;
    if(data[i+1].z==1 && data[i+1].x<p)
    {
    if(cnt-j+1<=K) upmax(F[i+1][j],F[i][j]+data[i+1].y); else upmax(F[i+1][j],F[i][j]);
    continue;
    }
    if(data[i+1].x>=p && j+1<=K)
    upmax(F[i+1][j+1],F[i][j]+data[i+1].x*data[i+1].z);
    if(cnt-j+1<=K) upmax(F[i+1][j],F[i][j]+data[i+1].y*data[i+1].z); else upmax(F[i+1][j],F[i][j]);
    }
    cnt++;
    }
    upmax(ans,F[N][K]);
    }
    cout<<ans<<endl;
    return 0;
    }
    View Code
     
    v
    数据结构题。
    对于每个点,分别求出其向上递增,递减,先增后减,先减后增的最长序列。
    然后运用倍增思想,t[i][j]表示从结点i向上的长为2^i的序列中的答案。
    GDKOI2015 - maijing3007 - maijing
     
    设k为i向上跳2^(j-1)步到达的点。
    容易知道答案要么全部在红色区域内(答案为t[i][j-1]),要么全部在蓝色区域内(答案为t[k][j-1]),或者跨过红色区域和蓝色区域,这时必然经过k。
    有4种情况:
    k下方最长的递增序列长度+k上方最长的先增后减序列长度-1
    k下方最长的递减序列长度+k上方最长的先减后增序列长度-1
    k下方最长的先增后减序列长度+k上方最长的递减序列长度-1
    k下方最长的先减后增序列长度+k上方最长的递增序列长度-1
    对于询问u,v:
    先求出lca。
    那么有2种情况,经过lca和不经过lca。
    经过lca可以类似于上面的4种情况讨论。
    不经过lca,就是从u到lca或者从v到lca,不失一般性,讨论从u到lca :
    GDKOI2015 - maijing3007 - maijing
    我们把从u到lca的路径分成若干段,其中每段的长度都是2的若干次方,可以证明不超过logn段。
    在每段内部,我们已经预处理好了,剩下的就是段与段之间的合并,还是利用上面的4种情况进行讨论。
    #include<cstdio>
    #include<cstdlib>
    #include<iostream>
    #include<fstream>
    #include<algorithm>
    #include<cstring>
    #include<string>
    #include<cmath>
    #include<queue>
    #include<stack>
    #include<map>
    #include<utility>
    #include<set>
    #include<bitset>
    #include<vector>
    #include<functional>
    
    using namespace std;
    
    typedef long long LL;
    typedef double DB;
    typedef pair<int,int> PII;
    
    #define mmst(a,v) memset(a,v,sizeof(a))
    #define mmcy(a,b) memcpy(a,b,sizeof(a))
    #define re(i,a,b) for(i=a;i<=b;i++)
    #define red(i,a,b) for(i=a;i>=b;i--)
    #define fi first
    #define se second
    
    template<class T>inline T sqr(T x){return x*x;}
    template<class T>inline void upmin(T &t,T tmp){if(t>tmp)t=tmp;}
    template<class T>inline void upmax(T &t,T tmp){if(t<tmp)t=tmp;}
    
    const DB EPS=1e-9;
    inline int dblcmp(DB x){if(abs(x)<EPS)return 0;return(x>0)?1:-1;}
    
    inline void SetOpen(string s)
    {
    freopen((s+".in").c_str(),"r",stdin);
    freopen((s+".out").c_str(),"w",stdout);
    }
    
    inline int Getin_Int()
    {
    int res=0,flag=1;char z;
    for(z=getchar();z!=EOF && z!='-' && !isdigit(z);z=getchar());
    if(z==EOF)return 0;
    if(z=='-'){flag=-flag;z=getchar();}
    for(;z!=EOF && isdigit(z);res=res*10+z-'0',z=getchar());
    return res*flag;
    }
    inline LL Getin_LL()
    {
    LL res=0,flag=1;char z;
    for(z=getchar();z!=EOF && z!='-' && !isdigit(z);z=getchar());
    if(z==EOF)return 0;
    if(z=='-'){flag=-flag;z=getchar();}
    for(;z!=EOF && isdigit(z);res=res*10+z-'0',z=getchar());
    return res*flag;
    }
    
    const int maxN=100000;
    
    int N,Q;
    int first[maxN+100],now;
    struct Tedge{int v,next;}edge[2*maxN+100];
    int fa[maxN+100],dep[maxN+100];
    int jump[maxN+100][50];
    int p[maxN+100][4];//0上升 1下降 2先上后下 3先下后上 
    int t[maxN+100][50];
    int ans;
    
    inline void addedge(int u,int v)
    {
    now++;
    edge[now].v=v;
    edge[now].next=first[u];
    first[u]=now;
    }
    
    int que[maxN+100],head,tail;
    inline void BFS(int S)
    {
    dep[que[head=tail=0]=S]=1;
    while(head<=tail)
    {
    int u=que[head++],i,v;
    for(i=first[u],v=edge[i].v;i!=-1;i=edge[i].next,v=edge[i].v)dep[que[++tail]=v]=dep[u]+1;
    }
    }
    
    inline int swim(int x,int H)
    {
    for(int i=0;H!=0;H/=2,i++)if(H&1)x=jump[x][i];
    return x;
    }
    inline int Ask_LCA(int x,int y)
    {
    if(dep[x]<dep[y]) swap(x,y);
    x=swim(x,dep[x]-dep[y]);
    if(x==y)return x;
    int i;
    red(i,30,0)if(jump[x][i]!=jump[y][i]){x=jump[x][i];y=jump[y][i];}
    return jump[x][0];
    }
    
    inline int up(int x,int y,int f)
    {
    return min(p[x][f],dep[x]-dep[y]+1);
    }
    inline int down(int x,int y,int f)
    {
    int l=0,r=dep[x]-dep[y],mid;
    while(l<=r)
    {
    mid=(l+r)/2;
    int temp=swim(x,mid);
    if(p[temp][f]>=dep[temp]-dep[y]+1) r=mid-1; else l=mid+1;
    }
    return dep[swim(x,l)]-dep[y]+1;
    }
    
    inline int solve(int a,int b)
    {
    int i,res=0,H=dep[a]-dep[b]+1,x=a,y;
    for(i=0;H!=0;H/=2,i++)if(H&1)
    {
    y=swim(x,(1<<i)-1);
    upmax(res,t[x][i]);
    if(a!=x)
    {
    upmax(res,down(a,x,0)+up(x,y,2)-1);
    upmax(res,down(a,x,1)+up(x,y,3)-1);
    upmax(res,down(a,x,2)+up(x,y,1)-1);
    upmax(res,down(a,x,3)+up(x,y,0)-1);
    }
    x=fa[y];
    }
    return res;
    }
    
    int main()
    {
    SetOpen("v");
    int i,j;
    N=Getin_Int();
    mmst(first,-1);now=-1;
    re(i,2,N){fa[i]=Getin_Int();addedge(fa[i],i);}
    BFS(1);
    re(i,0,30)jump[1][i]=1;
    re(j,1,tail)
    {
    int u=que[j];
    jump[u][0]=fa[u];
    re(i,1,30)jump[u][i]=jump[jump[u][i-1]][i-1];
    }
    re(j,0,tail)
    {
    int u=que[j];
    if(u<fa[u])p[u][0]=p[fa[u]][0]+1; else p[u][0]=1;
    if(u>fa[u])p[u][1]=p[fa[u]][1]+1; else p[u][1]=1;
    p[u][2]=p[u][1];if(u<fa[u])p[u][2]=max(p[fa[u]][2],p[fa[u]][1])+1;
    p[u][3]=p[u][0];if(u>fa[u])p[u][3]=max(p[fa[u]][3],p[fa[u]][0])+1;
    }
    re(j,0,tail)
    {
    int a=que[j],c,d;
    t[a][0]=1;
    re(i,1,30)
    {
    c=jump[a][i-1];
    d=swim(c,dep[a]-dep[c]-1);
    t[a][i]=max(t[a][i-1],t[c][i-1]);
    upmax(t[a][i],down(a,c,0)+up(c,d,2)-1);
    upmax(t[a][i],down(a,c,1)+up(c,d,3)-1);
    upmax(t[a][i],down(a,c,2)+up(c,d,1)-1);
    upmax(t[a][i],down(a,c,3)+up(c,d,0)-1);
    }
    }
    ans=0;
    Q=Getin_Int();
    while(Q--)
    {
    int u=Getin_Int()^ans,v=Getin_Int()^ans,lca;
    ans=0;
    lca=Ask_LCA(u,v);
    upmax(ans,solve(u,lca));
    upmax(ans,solve(v,lca));
    upmax(ans,down(u,lca,0)+down(v,lca,2)-1);
    upmax(ans,down(u,lca,1)+down(v,lca,3)-1);
    upmax(ans,down(u,lca,2)+down(v,lca,0)-1);
    upmax(ans,down(u,lca,3)+down(v,lca,1)-1);
    printf("%d
    ",ans);
    } 
    return 0;
    }
    View Code
    avenger
    待续......

     

  • 相关阅读:
    Red packet
    Pie
    River Hopscotch
    5.spring使用注解开发
    11.Java邮件发送
    10.Java文件传输
    HTML中标签的嵌套原则
    9.SMBMS超市订单管理系统
    8.MVC和过滤器Filter
    7.JSP基础语法,指令和标签以及Java Bean
  • 原文地址:https://www.cnblogs.com/maijing/p/4649408.html
Copyright © 2011-2022 走看看