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\n",ans/GCD,sum/GCD);
    return 0;   
}
posted @ 2019-02-14 14:59  Monster_Qi  阅读(430)  评论(0编辑  收藏  举报