• BZOJ3123: [Sdoi2013]森林(启发式合并&主席树)


    3123: [Sdoi2013]森林

    Time Limit: 20 Sec  Memory Limit: 512 MB
    Submit: 4813  Solved: 1420
    [Submit][Status][Discuss]

    Description

    Input

    第一行包含一个正整数testcase,表示当前测试数据的测试点编号。保证1≤testcase≤20。 
    第二行包含三个整数N,M,T,分别表示节点数、初始边数、操作数。第三行包含N个非负整数表示 N个节点上的权值。 
     接下来 M行,每行包含两个整数x和 y,表示初始的时候,点x和点y 之间有一条无向边, 接下来 T行,每行描述一个操作,格式为“Q x y k”或者“L x y ”,其含义见题目描述部分。

    Output

    对于每一个第一类操作,输出一个非负整数表示答案。 
     
     

    Sample Input

    1
    8 4 8
    1 1 2 2 3 3 4 4
    4 7
    1 8
    2 4
    2 1
    Q 8 7 3 Q 3 5 1
    Q 10 0 0
    L 5 4
    L 3 2 L 0 7
    Q 9 2 5 Q 6 1 6

    Sample Output

    2
    2
    1
    4
    2

    HINT



    对于第一个操作 Q 8 7 3,此时 lastans=0,所以真实操作为Q 8^0 7^0 3^0,也即Q 8 7 3。点8到点7的路径上一共有5个点,其权值为4 1 1 2 4。这些权值中,第三小的为 2,输出 2,lastans变为2。对于第二个操作 Q 3 5 1 ,此时lastans=2,所以真实操作为Q 3^2 5^2 1^2 ,也即Q 1 7 3。点1到点7的路径上一共有4个点,其权值为 1 1 2 4 。这些权值中,第三小的为2,输出2,lastans变为 2。之后的操作类似。 


    思路:题意输入的case不要管,此题不是多组输入。 我们求路径第k大,优先会想到主席树,但是这里有合并的操作,事实上启发式够用了。

    至于倍增LCA,我们可以dfs的时候就维护。

    #include<bits/stdc++.h>
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    using namespace std;
    const int maxn=80010;
    struct in{
        int l,r,sum;
        in(){l=r=sum=0;}
        in(int L,int R,int S):l(L),r(R),sum(S){}
    }s[10000010];
    int Laxt[maxn],Next[maxn<<1],To[maxn<<1],rt[maxn],cnt,scc_cnt,N,ans;
    int a[maxn],b[maxn],fa[maxn][17],tot,scc[maxn],sz[maxn],dep[maxn],num;
    void read(int &x){
        x=0; char c=getchar();
        while(c>'9'||c<'0') c=getchar();
        while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
    }
    void add(int u,int v){ Next[++cnt]=Laxt[u]; Laxt[u]=cnt; To[cnt]=v;}
    void update(int &Now,int pre,int L,int R,int pos)
    {
        Now=++num; s[Now]=s[pre]; s[Now].sum++;
        if(L==R) return ; int Mid=(L+R)>>1;
        if(pos<=Mid) update(s[Now].l,s[pre].l,L,Mid,pos);
        else update(s[Now].r,s[pre].r,Mid+1,R,pos);
    }
    void dfs(int u,int f,int p)
    {
        update(rt[u],rt[f],1,tot,a[u]); dep[u]=dep[f]+1;
        fa[u][0]=f; scc[u]=p; sz[p]++;
        rep(j,1,16) fa[u][j]=fa[fa[u][j-1]][j-1];
        for(int i=Laxt[u];i;i=Next[i]) if(To[i]!=f) dfs(To[i],u,p);
    }
    void Connect(int x,int y)
    {
        if(sz[scc[x]]<sz[scc[y]]) swap(x,y);
        dfs(y,x,scc[x]);
    }
    int query(int u,int v,int Lca,int old,int L,int R,int k)
    {
        if(L==R) return L; int Mid=(L+R)>>1;
        int tmp=s[s[u].l].sum+s[s[v].l].sum-s[s[Lca].l].sum-s[s[old].l].sum;
        if(tmp>=k) return query(s[u].l,s[v].l,s[Lca].l,s[old].l,L,Mid,k);
        return query(s[u].r,s[v].r,s[Lca].r,s[old].r,Mid+1,R,k-tmp);
    }
    int LCA(int u,int v)
    {
        if(dep[u]<dep[v]) swap(u,v);
        for(int i=16;i>=0;i--) if(dep[fa[u][i]]>=dep[v]) u=fa[u][i];
        if(u==v) return u;
        for(int i=16;i>=0;i--) if(fa[u][i]!=fa[v][i]) u=fa[u][i],v=fa[v][i];
        return fa[u][0];
    }
    void Query(int u,int v,int k)
    {
        int Lca=LCA(u,v);
        ans=b[query(rt[u],rt[v],rt[Lca],rt[fa[Lca][0]],1,tot,k)];
        printf("%d
    ",ans);
    }
    int main()
    {
        int C,M,T,u,v,x,y,k;
        scanf("%d%d%d%d",&C,&N,&M,&T);
        rep(i,1,N) read(a[i]),b[i]=a[i];
        sort(b+1,b+N+1); tot=unique(b+1,b+N+1)-(b+1);
        rep(i,1,N) a[i]=lower_bound(b+1,b+tot+1,a[i])-b;
        rep(i,1,M){
            read(u); read(v);
            add(u,v); add(v,u);
        }
        char opt[3];
        rep(i,1,N) if(!scc[i]) dfs(i,0,++scc_cnt);
        while(T--){
            scanf("%s",opt);
            if(opt[0]=='Q'){
                read(x); read(y); read(k);
                x=ans^x; y=ans^y; k=ans^k;
                Query(x,y,k);
            }
            else {
                scanf("%d%d",&x,&y);
                x=ans^x; y=ans^y; add(x,y); add(y,x);
                Connect(x,y);
            }
        }
        return 0;
    }
  • 相关阅读:
    【MySQL疑难杂症】如何将树形结构存储在数据库中(方案二 Path Enumeration)
    【MySQL疑难杂症】如何将树形结构存储在数据库中(方案一 Adjacency List)
    【Java疑难杂症】利用Java核心库实现简单的AOP
    【Java入门提高篇】Day5 Java中的回调(二)
    【Java入门提高篇】Day4 Java中的回调
    【SpringMVC】使用Myeclipse创建SpringMVC项目【超详细教程】
    使用GDAL/OGR读写矢量文件
    WebGL简易教程(四):颜色
    WebGL简易教程(三):绘制一个三角形(缓冲区对象)
    OSG与Shader的结合使用
  • 原文地址:https://www.cnblogs.com/hua-dong/p/9993494.html
Copyright © 2020-2023  润新知