zoukankan      html  css  js  c++  java
  • luoguP4899 [IOI2018] werewolf 狼人 Kruskal重构树+倍增+主席树

    没调完呀,感觉代码能力还是有待提高......    

    写代码一定要讲究结构 + 逻辑性.   

    如果结构或者逻辑性不好的话是非常非常遭罪的 QAQ......  

    upd:好像调了 5 分钟就过了

    这个问题等价于求:$x$ 能到达一个点集, $y$ 也能到达一个点集,这两个点集是否有交集 ? 

    由于是否到达只有边权最大/最小值决定,所以就建立两颗 kruskal 重构树,然后判断两个子树是否有交集即可.  

    判断方式是主席树/树套树.   

    说实话这种硬核数据结构题反倒比那些 DP 什么的好写,好调.     

    code:  

    #include <bits/stdc++.h>      
    #define N 400009   
    #define ll long long 
    #define setIO(s) freopen(s".in","r",stdin) 
    // double check !!!    
    using namespace std;  
    int n,m,Q,cnt=0,M;  
    int v1[N],v2[N],rt[N];      
    struct UNI 
    {   
        int p[N];  
        void init() { for(int i=0;i<N;++i) p[i]=i; }   
        int find(int x) { return p[x]==x?x:p[x]=find(p[x]); }        
    }s1,b1;    
    struct SEG 
    {    
        #define lson s[x].ls 
        #define rson s[x].rs 
        int tot;    
        struct data { int sum,ls,rs; } s[N*50];       
        void build(int &x,int l,int r) 
        {  
            x=++tot;  
            if(l==r) return;   
            int mid=(l+r)>>1;  
            build(lson,l,mid),build(rson,mid+1,r);  
        }
        int update(int x,int l,int r,int p,int v) 
        { 
            int now=++tot;   
            s[now]=s[x];   
            s[now].sum+=v;   
            if(l==r) return now;  
            int mid=(l+r)>>1; 
            if(p<=mid)  s[now].ls=update(s[x].ls,l,mid,p,v);  
            else s[now].rs=update(s[x].rs,mid+1,r,p,v);  
            return now;  
        }
        int query(int x,int y,int l,int r,int L,int R) 
        {   
            if(!x) return 0; 
            if(l>=L&&r<=R) return s[y].sum-s[x].sum;  
            int mid=(l+r)>>1,re=0;   
            if(L<=mid)  re+=query(s[x].ls,s[y].ls,l,mid,L,R);  
            if(R>mid)   re+=query(s[x].rs,s[y].rs,mid+1,r,L,R);   
            return re;   
        }
        #undef lson 
        #undef rson 
    }se;  
    struct SMA 
    {   
        int x,y;  
        SMA(int x=0,int y=0):x(x),y(y){}   
        bool operator<(const SMA b) const { return min(x,y)>min(b.x,b.y); }   
    }sm[N]; 
    struct BIG 
    {  
        int x,y; 
        BIG(int x=0,int y=0):x(x),y(y){}   
        bool operator<(const BIG b) const { return max(x,y)<max(b.x,b.y); }   
    }bi[N];        
    struct G 
    {
        int edges,tim; 
        int bin[N<<1];  
        int hd[N<<1],to[N<<1],nex[N<<1],st[N<<1],ed[N<<1],fa[20][N<<1];  
        void add(int u,int v) 
        {
            nex[++edges]=hd[u],hd[u]=edges,to[edges]=v;  
        }   
        void dfs(int x) 
        {  
            ++tim;
            st[x]=tim,bin[tim]=x;     
            for(int i=1;i<20;++i)  fa[i][x]=fa[i-1][fa[i-1][x]];  
            for(int i=hd[x];i;i=nex[i])  fa[0][to[i]]=x,dfs(to[i]);   
            ed[x]=tim;  
        }    
    }G1,G2;     
    // 递减,即寻找最靠上大于等于 val 的   
    int get_sm(int x,int val) 
    {
        for(int i=19;i>=0;--i)  if(G1.fa[i][x]&&v1[G1.fa[i][x]]>=val) x=G1.fa[i][x];  
        return x; 
    }
    // 递增,即寻找最靠上小于等于 val 的   
    int get_bi(int x,int val) 
    {
        for(int i=19;i>=0;--i)  if(G2.fa[i][x]&&v2[G2.fa[i][x]]<=val) x=G2.fa[i][x];   
        return x;   
    }
    void build_sm() 
    {  
        s1.init();  
        sort(sm+1,sm+1+cnt);      
        int x,y,z,tot=n;     
        for(int i=1;i<=cnt;++i) 
        {        
            x=sm[i].x,y=sm[i].y,z=min(sm[i].x,sm[i].y);                
            x=s1.find(x),y=s1.find(y);  
            if(x!=y)         
            { 
                ++tot;                    
                G1.add(tot,x);   
                G1.add(tot,y);     
                s1.p[x]=s1.p[y]=tot,v1[tot]=z;      
            }
        }      
        G1.dfs(tot);     
    }
    void build_bi() 
    { 
        b1.init();  
        sort(bi+1,bi+1+cnt);   
        int x,y,z,tot=n;  
        for(int i=1;i<=cnt;++i)  
        {
            x=bi[i].x,y=bi[i].y,z=max(bi[i].x,bi[i].y);   
            x=b1.find(x),y=b1.find(y);   
            if(x!=y) 
            {
                ++tot;   
                G2.add(tot,x); 
                G2.add(tot,y);   
                b1.p[x]=b1.p[y]=tot,v2[tot]=z;        
            }
        }
        M=tot;  
        G2.dfs(tot);             
        se.build(rt[0],1,tot);        
        for(int i=1;i<=tot;++i) 
        {
            if(G2.bin[i]<=n)            
                rt[i]=se.update(rt[i-1],1,tot,G1.st[G2.bin[i]],1);   
            else rt[i]=rt[i-1];  
        }             
    }
    char *p1,*p2,buf[100000];  
    #define nc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++)   
    int rd() 
    {
        int x=0; char c;  
        while(c<48) c=nc();   
        while(c>47) x=(((x<<2)+x)<<1)+(c^48),c=nc();  
        return x;  
    }
    int main() 
    { 
        // setIO("input");     
        int x,y,z,s,t,l,r;  
        n=rd(),m=rd(),Q=rd();             
        for(int i=1;i<=m;++i) 
        {
            x=rd()+1,y=rd()+1,++cnt; 
            sm[cnt]=SMA(x,y),bi[cnt]=BIG(x,y);  
        } 
        build_sm();  
        build_bi();                  
        for(int i=1;i<=Q;++i) 
        {
            s=rd()+1,t=rd()+1;  
            l=rd()+1,r=rd()+1;   
            // 去:[l,n] 
            // 回:[1,r]   
            x=get_sm(s,l);    // G1
            y=get_bi(t,r);    // G2 
            int L=G1.st[x],R=G1.ed[x];   
            int r1=G2.ed[y],r2=G2.st[y]-1;   
            if(se.query(rt[r2],rt[r1],1,M,L,R)) printf("1
    "); 
            else printf("0
    ");     
        }   
        return 0; 
    }       
    

      

  • 相关阅读:
    LeetCode5 Longest Palindromic Substring
    LeetCode4 Median of Two Sorted Arrays
    LeetCode3 Longest Substring Without Repeating Characters
    LeetCode2 Add Two Numbers
    LeetCode1 Two Sum
    算法总结—深度优先搜索DFS
    c++ 设计模式9 (Abstract Factory 抽象工厂模式)
    题解 P3374 【【模板】树状数组 1】
    题解 HDU1565 【方格取数(1)】
    题解 P2431 【正妹吃月饼】
  • 原文地址:https://www.cnblogs.com/guangheli/p/13067020.html
Copyright © 2011-2022 走看看