zoukankan      html  css  js  c++  java
  • 训练赛第二场补题&&总结(更新中)

    B题:

    比赛的时候我又没仔细看题,又把题目读错了。。。虽然读对的话我也不一定能想出如何用加权并查集做。比赛的时候我的第一感觉就是splay模拟,赛后写了一下,TLE了。。。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    #define REP(i,a,b) for(int i=a;i<=b;i++)
    #define MS0(a) memset(a,0,sizeof(a))
    #define key_val ch[ch[rt][1]][0]
    
    using namespace std;
    
    typedef long long ll;
    const int maxn=1000100;
    const int INF=1e9+10;
    
    int n,q;
    char op[10];int x,y;
    int node[maxn];/// node[x] x所在结点
    ///--- splay
    int pre[maxn],ch[maxn][2];
    int val[maxn];
    int sz[maxn];
    int tot1,s[maxn],tot2;
    
    void newnode(int &x,int fa,int k)
    {
        if(tot2) x=s[tot2--];
        else x=++tot1;
        pre[x]=fa;
        val[x]=k;
        sz[x]=1;
        MS0(ch[x]);
    }
    
    void up(int x)
    {
        sz[x]=sz[ch[x][0]]+sz[ch[x][1]]+1;
    }
    
    void rot(int x,int kind)
    {
        int y=pre[x];
        ch[y][kind^1]=ch[x][kind];
        pre[ch[x][kind]]=y;
        if(pre[y]) ch[pre[y]][ch[pre[y]][1]==y]=x;
        pre[x]=pre[y];
        ch[x][kind]=y;
        pre[y]=x;
        up(y);
    }
    
    void splay(int x,int goal)
    {
        while(pre[x]!=goal){
            if(pre[pre[x]]==goal) rot(x,ch[pre[x]][0]==x);
            else{
                int y=pre[x],z=pre[y];
                int kind=ch[y][0]==x,one=0;
                if(ch[y][0]==x&&ch[z][0]==y) one=1;
                if(ch[y][1]==x&&ch[z][1]==y) one=1;
                if(one) rot(y,kind),rot(x,kind);
                else rot(x,kind),rot(x,kind^1);
            }
        }
        up(x);
    }
    
    void Init_splay()
    {
        pre[0]=0;
        MS0(ch[0]);
        sz[0]=0;
        tot1=tot2=0;
    }
    
    void Init()
    {
        Init_splay();
        int rt;
        REP(i,1,n) newnode(rt,0,i),node[i]=rt;
    }
    
    ///----solve
    int Calc(int x)
    {
        int y=node[x];
        splay(y,0);
        return sz[ch[y][0]];
    }
    
    void Put(int x,int y)
    {
        int z=node[x],w=node[y];
        if(z==w) return;
        splay(z,0);
        while(ch[z][0]) z=ch[z][0];
        splay(z,0);
        splay(w,0);
        ch[z][0]=w;
        pre[w]=z;
        splay(w,0);
    }
    
    int main()
    {
        freopen("in.txt","r",stdin);
        while(~scanf("%d",&q)){
            n=30010;
            Init();
            REP(i,1,q){
                scanf("%s",op);
                if(op[0]=='M'){
                    scanf("%d%d",&x,&y);
                    Put(x,y);
                }
                else{
                    scanf("%d",&x);
                    printf("%d
    ",Calc(x));
                }
            }
        }
        return 0;
    }
    View Code

    没办法,学并查集的思路吧,作为专搞数据结构的,这种加权并查集的题目没做出来实在惭愧。。

     好了,我已经知道会这道题了,并不是我思维不行,实在是这是我做的第一道加权并查集的题目。加权并查集就是将x和fa[x]这条树边的边权存在x的点权中,查找路径压缩的时候先find再改边权,因为是往上寻找,所以从祖先开始往下更新,说的比较含糊,其实是很简单很容易理解的东西。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    #define REP(i,a,b) for(int i=a;i<=b;i++)
    #define MS0(a) memset(a,0,sizeof(a))
    
    using namespace std;
    
    typedef long long ll;
    const int maxn=1000100;
    const int INF=1e9+10;
    
    int n,q;
    int fa[maxn],sz[maxn],w[maxn];
    char op[10];int x,y;
    
    int find(int x)
    {
        if(fa[x]==x) return x;
        int t=find(fa[x]);
        w[x]+=w[fa[x]];
        return fa[x]=t;
    }
    
    void Union(int u,int v)
    {
        int x=find(u),y=find(v);
        if(x==y) return;
        fa[x]=y;
        w[x]=sz[y];
        sz[y]+=sz[x];
    }
    
    int main()
    {
        #ifndef ONLINE_JUDGE
            freopen("in.txt","r",stdin);
        #endif // ONLINE_JUDGE
        while(~scanf("%d",&q)){
            n=30010;
            REP(i,0,n) fa[i]=i,w[i]=0,sz[i]=1;
            while(q--){
                scanf("%s",op);
                if(op[0]=='M') scanf("%d%d",&x,&y),Union(x,y);
                else scanf("%d",&x),find(x),printf("%d
    ",w[x]);
            }
        }
        return 0;
    }
    /**
    
    10
    M 1 6
    M 2 4
    M 2 6
    M 6 5
    C 1
    C 2
    C 3
    C 4
    C 5
    C 6
    5
    M 1 6
    M 2 4
    M 2 6
    M 6 5
    C 2
    */
    View Code
    没有AC不了的题,只有不努力的ACMER!
  • 相关阅读:
    JavaScript-年月日转换12小时制
    Javascript-双色球
    Javascript-for循环案例-打印1-100之间所有的数字
    HDU4240_Route Redundancy
    HDU2883_kebab
    POJ3041_Asteroids
    HDU3829_Cat VS Dog
    BZOJ2806_Cheat
    HDU4641_K-string
    CF271D_Good Substrings
  • 原文地址:https://www.cnblogs.com/--560/p/5268052.html
Copyright © 2011-2022 走看看