[BZOJ 3772]精神污染 主席树+dfs序

来源:互联网 发布:端口号80是什么意思 编辑:程序博客网 时间:2024/05/21 11:20

这题目描述是真...精神污染..

比较有趣的一道题目,首先显然ans=所有两两之间有包含关系的路径/所有的方案数

那么,现在问题就变成了如何快速的找到有包含关系的路径.

假设现在有路径A以及路径B,切A包含于B,那么显然A的两个端点都在B这条路径上,也就是说我们只需要找到所有起点和终点都在B路径上面的路径.这里由于路径很难维护,所有就维护当前节点到根节点的信息.

主席树维护dfs序(每一个点都有入栈和出栈不同的编号)

这里主席树维护的信息是:对于每一个节点的树是以这个节点为起点的终点区间和,所以整个主席树就是以这个节点到根节点之间的这一部分节点为起点的终点.而且入栈为1,出栈为-1,这样只用查询in[rt]->in[u]就是跟到节点之间的信息,其他的+1和-1相互抵消

剩下的随便++--就好了

#include<cstdio>#include<cstring>#include<iostream>#include<vector>#define LL long long#define maxn 100005using namespace std;vector<int>g[maxn];LL A,B;int head[maxn],tot=1,in[maxn],out[maxn],sz,h[maxn],cnt,rt[maxn];int f[maxn][17],sum[maxn*38],rs[maxn*38],ls[maxn*38],n,m;struct que{int x,y;}q[maxn];struct edge{int v,next;}e[maxn*2];void adde(int a,int b){e[tot].v=b,e[tot].next=head[a];head[a]=tot++;}LL gcd(LL a,LL b){return !b ? a : gcd(b,a%b);}void insert(int x,int& y,int l,int r,int id,int add){y=++cnt;ls[y]=ls[x],rs[y]=rs[x],sum[y]=sum[x]+add;if(l==r)return;int mid=l+r>>1;if(id>mid)insert(rs[x],rs[y],mid+1,r,id,add);else insert(ls[x],ls[y],l,mid,id,add);}int query(int x,int a,int y,int b,int l,int r,int s,int t){if(s==l&&t==r)return sum[x]+sum[a]-sum[b]-sum[y];int mid=l+r>>1;if(s>mid)return query(rs[x],rs[a],rs[y],rs[b],mid+1,r,s,t);else if(t<=mid)return query(ls[x],ls[a],ls[y],ls[b],l,mid,s,t);else return query(rs[x],rs[a],rs[y],rs[b],mid+1,r,mid+1,t)+            query(ls[x],ls[a],ls[y],ls[b],l,mid,s,mid);}void dfs1(int u,int fa){f[u][0]=fa,h[u]=h[fa]+1;in[u]=++sz;for(int i=1;i<=16;i++)f[u][i]=f[f[u][i-1]][i-1];for(int v,i=head[u];i;i=e[i].next){if((v=e[i].v)==fa)continue;dfs1(v,u);}out[u]=++sz;}void dfs2(int u,int fa){rt[u]=rt[fa];for(int i=0;i<g[u].size();i++){insert(rt[u],rt[u],1,sz,in[g[u][i]],1);insert(rt[u],rt[u],1,sz,out[g[u][i]],-1);}for(int v,i=head[u];i;i=e[i].next){if((v=e[i].v)==fa)continue;dfs2(v,u);}}int lca(int a,int b){if(h[a]>h[b])swap(a,b);for(int i=16;i>=0;i--)if(h[f[b][i]]>=h[a])b=f[b][i];if(a==b)return a;for(int i=16;i>=0;i--){if(f[a][i]==f[b][i])continue;a=f[a][i],b=f[b][i];}return f[a][0];}void solve(){int a,b,g,fg;for(int i=1;i<=m;i++){a=q[i].x,b=q[i].y,g=lca(a,b),fg=f[g][0];A--;A+=query(rt[a],rt[b],rt[g],rt[fg],1,sz,in[g],in[a]);A+=query(rt[a],rt[b],rt[g],rt[fg],1,sz,in[g],in[b]);A-=query(rt[a],rt[b],rt[g],rt[fg],1,sz,in[g],in[g]);}}int main(){scanf("%d%d",&n,&m);for(int a,b,i=1;i<n;i++){scanf("%d%d",&a,&b);adde(a,b),adde(b,a);}for(int a,b,i=1;i<=m;i++){scanf("%d%d",&a,&b);g[a].push_back(b);q[i]=(que){a,b};}dfs1(1,0);dfs2(1,0);solve();B=(LL)m*(m-1)/2;LL t=gcd(A,B);A/=t,B/=t;printf("%lld/%lld",A,B);return 0;}


0 0
原创粉丝点击