• BZOJ 3772: 精神污染(dfs序+主席树)


    传送门

    解题思路

      比较神仙的一道题。首先计算答案时可以每条路径所包含的路径数,对于(x,y)这条路径,可以在(x)这处开个(vector)(y),然后计算时只需要算这个路径上每个点的(vector)中的元素是否也在这条路径上。这个可以用主席树维护,主席树维护括号序列,进时(+1),出时(-1),然后加加减减算一下。这题卡空间。。

    代码

    #include<bits/stdc++.h>
     
    using namespace std;
    const int N=100005;
    const int M=N*38;
    typedef long long LL;
     
    inline int rd(){
        int x=0,f=1; char ch=getchar();
        while(!isdigit(ch)) f=ch=='-'?0:1,ch=getchar();
        while(isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
        return f?x:-x;  
    }
     
    int n,m,head[N],cnt,to[N<<1],nxt[N<<1],xx[N],yy[N],siz[N],son[N];
    int rt[N<<1],fa[N],top[N],in[N],num,out[N],tot,dep[N];
    LL ans,sum;
    vector<int> v[N];
     
    struct Segment_Tree{
        int ls[M],rs[M],sum[M];
        void build(int &x,int l,int r){
            x=++tot; if(l==r) return ;
            int mid=(l+r)>>1;
            build(ls[x],l,mid); build(rs[x],mid+1,r);   
        }
        int update(int pre,int l,int r,int pos,int k){
            int now=++tot,mid=(l+r)>>1;
            if(l==r) {sum[now]=sum[pre]+k; return now;}
            if(pos<=mid) rs[now]=rs[pre],ls[now]=update(ls[pre],l,mid,pos,k);
            else ls[now]=ls[pre],rs[now]=update(rs[pre],mid+1,r,pos,k);
            sum[now]=sum[ls[now]]+sum[rs[now]];
            return now;
        }
        int query(int x,int y,int lca,int F,int l,int r,int L,int R){
            if(L>R) return 0;
            if(L==l && r==R) return sum[x]+sum[y]-sum[lca]-sum[F];
            int mid=(l+r)>>1;
            if(R<=mid) return query(ls[x],ls[y],ls[lca],ls[F],l,mid,L,R);
            else if(L>mid) return query(rs[x],rs[y],rs[lca],rs[F],mid+1,r,L,R);
            else return query(ls[x],ls[y],ls[lca],ls[F],l,mid,L,mid)+query(rs[x],rs[y],rs[lca],rs[F],mid+1,r,mid+1,R);
        }
        int ask(int x,int l,int r,int L,int R){
            if(L<=l && r<=R) return sum[x];
            int mid=(l+r)>>1,ret=0;
            if(L<=mid) ret+=ask(ls[x],l,mid,L,R);
            if(mid<R) ret+=ask(rs[x],mid+1,r,L,R);
            return ret; 
        }
    }tree;
     
    inline void add(int bg,int ed){
        to[++cnt]=ed,nxt[cnt]=head[bg],head[bg]=cnt;    
    }
     
    void dfs(int x,int F){
        in[x]=++num; fa[x]=F; siz[x]=1; int maxson=-1;
        for(int i=head[x];i;i=nxt[i]){
            int u=to[i]; if(u==F) continue;
            dep[u]=dep[x]+1; dfs(u,x); 
            siz[x]+=siz[u];
            if(siz[u]>maxson) maxson=siz[u],son[x]=u;
        }
        out[x]=++num;
    }
     
    void dfs2(int x,int F){
        rt[x]=rt[F];
        for(int i=0;i<v[x].size();i++) {
            rt[x]=tree.update(rt[x],1,2*n,in[v[x][i]],1);
            rt[x]=tree.update(rt[x],1,2*n,out[v[x][i]],-1); 
        }
        for(int i=head[x];i;i=nxt[i]){
            int u=to[i]; if(u==F) continue;
            dfs2(u,x);  
        }
    }
    
    void dfs3(int x,int topf){
    	top[x]=topf; if(!son[x]) return;
    	dfs3(son[x],topf);
    	for(int i=head[x];i;i=nxt[i]){
    		int u=to[i]; if(u==fa[x] || u==son[x]) continue;
    		dfs3(u,u);
    	}
    }
     
    inline int LCA(int x,int y){
    	while(top[x]!=top[y]){
    		if(dep[top[x]]>=dep[top[y]]) x=fa[top[x]];
    		else y=fa[top[y]];
    	}
    	return dep[x]>dep[y]?y:x;
    }
     
    int main(){
        n=rd(),m=rd(); int x,y,lca;
        for(register int i=1;i<n;i++){
            x=rd(),y=rd();
            add(x,y),add(y,x);
        } 
        for(register int i=1;i<=m;i++){
            x=rd(),y=rd();
            xx[i]=x,yy[i]=y;
            v[x].push_back(y);  
        } dep[1]=1;
        dfs(1,0); dfs2(1,0); dfs3(1,1);
        for(register int i=1;i<=m;i++){
            x=xx[i],y=yy[i],lca=LCA(x,y);
            ans+=tree.query(rt[x],rt[y],rt[lca],rt[fa[lca]],1,2*n,in[lca],in[x]);
            ans+=tree.query(rt[x],rt[y],rt[lca],rt[fa[lca]],1,2*n,in[lca],in[y]);
            ans-=tree.query(rt[x],rt[y],rt[lca],rt[fa[lca]],1,2*n,in[lca],in[lca]);
            ans--;
        }
        sum=(LL)m*(m-1)/2; LL GCD=__gcd(ans,sum);
        printf("%lld/%lld
    ",ans/GCD,sum/GCD);
        return 0;   
    }
    
  • 相关阅读:
    CCNode作为容器实现显示区域剪裁
    使用CCNode作为容器容易踩的坑
    走了很多弯路的CCScrollView
    常用es6特性归纳-(一般用这些就够了)
    WebP图片优化
    es6 Promise 异步函数调用
    网站性能优化
    dom元素分屏加载
    js顺序加载与并行加载
    移动端真机调试
  • 原文地址:https://www.cnblogs.com/sdfzsyq/p/10374645.html
Copyright © 2020-2023  润新知