【bzoj3772】 精神污染 dfs序+主席树
2015-08-06 15:56
447 查看
PoPoQQQ的题解太神了,表示看了好久才看懂,于是自己写了一份题解祸害人类。
首先有一个结论对于一条路径x-->y,如果它的两个端点x和y都在另一条路径上,则这条路径被另一条路径包含。
那么问题转化为了对于一条路径,判断两个端点都在这条路径上的路径有多少条。
那么对于每一个节点x,我们用一个vector来存节点y,当且仅当存在一条路径x-->y。
我们说主席树相当于前缀和S,那么我们现在要维护的序列A(即要维护前缀和的序列)表示什么呢?
在主席树中每一个节点的A都是一个序列,序列的下标表示的是每个节点的入栈序和出栈序,那么我们对于每一个节点x,将它的vector中的y节点的入栈序和出栈序在它的A序列中+1和-1,那么我们看一下,假设有路径x-->y,又有路径x-->z,那么后者包含前者时,y的入栈序一定在z的入栈序和出栈序之间,y的出栈序一定在z的出栈序之后,那么我们查询的时候就可以直接查询z的入出栈序之间的权值和,即为有多少条一端是x节点的路径被路径x-->z包含。
那么在树上建主席树,主席树的前缀和S就可以表示从根节点到这个节点x的路径上的A序列的和,那么查询时我们查询权值(下标)在lca(x,y)与y的入栈序之间的数的个数就是查询起点在根节点到x的路径上的终点在lca(x,y)与y之间的路径的个数。
那么被路径x-->y包含的路径数目就是,记z为lca(x,y),
ans=query(in[x])+query(in[y])-query(in[z])-query(in[fa[z]])-1
其中query操作是在第x棵、第y棵、第z棵、第fa[z]棵中找权值(下标)在1-k之间的数的和,这四颗树可以提前提取出来,最后的-1是把自己给减去。
最后要处理一下相同路径的问题。
然后并不知道为什么我直接询问前缀和会出错,但是如果区间查询的话就没有问题,这道题因为把4棵树提取出来还要写区间查询太麻烦了,所以直接放在函数里了。(原来可以区间查询呀,貌似跟普通的线段树一样呢)
首先有一个结论对于一条路径x-->y,如果它的两个端点x和y都在另一条路径上,则这条路径被另一条路径包含。
那么问题转化为了对于一条路径,判断两个端点都在这条路径上的路径有多少条。
那么对于每一个节点x,我们用一个vector来存节点y,当且仅当存在一条路径x-->y。
我们说主席树相当于前缀和S,那么我们现在要维护的序列A(即要维护前缀和的序列)表示什么呢?
在主席树中每一个节点的A都是一个序列,序列的下标表示的是每个节点的入栈序和出栈序,那么我们对于每一个节点x,将它的vector中的y节点的入栈序和出栈序在它的A序列中+1和-1,那么我们看一下,假设有路径x-->y,又有路径x-->z,那么后者包含前者时,y的入栈序一定在z的入栈序和出栈序之间,y的出栈序一定在z的出栈序之后,那么我们查询的时候就可以直接查询z的入出栈序之间的权值和,即为有多少条一端是x节点的路径被路径x-->z包含。
那么在树上建主席树,主席树的前缀和S就可以表示从根节点到这个节点x的路径上的A序列的和,那么查询时我们查询权值(下标)在lca(x,y)与y的入栈序之间的数的个数就是查询起点在根节点到x的路径上的终点在lca(x,y)与y之间的路径的个数。
那么被路径x-->y包含的路径数目就是,记z为lca(x,y),
ans=query(in[x])+query(in[y])-query(in[z])-query(in[fa[z]])-1
其中query操作是在第x棵、第y棵、第z棵、第fa[z]棵中找权值(下标)在1-k之间的数的和,这四颗树可以提前提取出来,最后的-1是把自己给减去。
最后要处理一下相同路径的问题。
然后并不知道为什么我直接询问前缀和会出错,但是如果区间查询的话就没有问题,这道题因为把4棵树提取出来还要写区间查询太麻烦了,所以直接放在函数里了。(原来可以区间查询呀,貌似跟普通的线段树一样呢)
#include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<iostream> #include<algorithm> #include<vector> #define maxn 100010 #define maxm 4000010 using namespace std; struct yts { int x,y; }q[maxn]; int lch[maxm],rch[maxm],cnt[maxm]; int to[2*maxn],next[2*maxn],head[maxn],root[maxn]; int in[maxn],out[maxn],c[5]; int dep[maxn],fa[maxn][20]; int n,m,tot,num,num1; vector<int> b[maxn]; long long gcd(long long a,long long b) { if (b==0) return a; else return gcd(b,a%b); } void addedge(int x,int y) { num++;to[num]=y;next[num]=head[x];head[x]=num; } void dfs(int x) { in[x]=++num1; for (int p=head[x];p;p=next[p]) if (to[p]!=fa[x][0]) { fa[to[p]][0]=x;dep[to[p]]=dep[x]+1; dfs(to[p]); } out[x]=++num1; } int modify(int pre,int l,int r,int x,int f) { int now=++tot; if (l==r) { cnt[now]=cnt[pre]+f;lch[now]=rch[now]=0; } else { int mid=(l+r)/2; if (x<=mid) { rch[now]=rch[pre];lch[now]=modify(lch[pre],l,mid,x,f); } else { lch[now]=lch[pre];rch[now]=modify(rch[pre],mid+1,r,x,f); } cnt[now]=cnt[lch[now]]+cnt[rch[now]]; } return now; } int query(int root1,int root2,int root3,int root4,int l,int r,int x,int y) { if (l==x && y==r) return cnt[root1]+cnt[root2]-cnt[root3]-cnt[root4]; int mid=(l+r)/2; if (y<=mid) return query(lch[root1],lch[root2],lch[root3],lch[root4],l,mid,x,y); if (mid<x) return query(rch[root1],rch[root2],rch[root3],rch[root4],mid+1,r,x,y); return query(lch[root1],lch[root2],lch[root3],lch[root4],l,mid,x,mid)+query(rch[root1],rch[root2],rch[root3],rch[root4],mid+1,r,mid+1,y); } void dfs1(int x) { root[x]=root[fa[x][0]]; for (int i=0;i<b[x].size();i++) { root[x]=modify(root[x],1,2*n,in[b[x][i]],1); root[x]=modify(root[x],1,2*n,out[b[x][i]],-1); } for (int p=head[x];p;p=next[p]) if (to[p]!=fa[x][0]) dfs1(to[p]); } int go_up(int x,int d) { for (int i=19;i>=0;i--) if (d&(1<<i)) x=fa[x][i]; return x; } int LCA(int x,int y) { if (dep[x]>dep[y]) x=go_up(x,dep[x]-dep[y]); else y=go_up(y,dep[y]-dep[x]); if (x==y) return x; for (int i=19;i>=0;i--) if (fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i]; return fa[x][0]; } bool cmp(yts a,yts b) { return a.x<b.x || (a.x==b.x && a.y<b.y); } int main() { scanf("%d%d",&n,&m); for (int i=1;i<n;i++) { int x,y; scanf("%d%d",&x,&y); addedge(x,y);addedge(y,x); } for (int i=1;i<=m;i++) { scanf("%d%d",&q[i].x,&q[i].y); b[q[i].x].push_back(q[i].y); } dep[1]=0;fa[1][0]=0; dfs(1); for (int j=1;j<=19;j++) for (int i=1;i<=n;i++) if (fa[i][j-1]) fa[i][j]=fa[fa[i][j-1]][j-1]; else fa[i][j]=0; long long ans=0; tot=0;root[0]=lch[0]=rch[0]=cnt[0]=0; dfs1(1); for (int i=1;i<=m;i++) { int x=q[i].x,y=q[i].y,z=LCA(x,y); ans+=query(root[x],root[y],root[z],root[fa[z][0]],1,2*n,in[z],in[x]); ans+=query(root[x],root[y],root[z],root[fa[z][0]],1,2*n,in[z],in[y]); ans-=query(root[x],root[y],root[z],root[fa[z][0]],1,2*n,in[z],in[z]); ans--; } sort(q+1,q+m+1,cmp); int j; for (int i=1;i<=m;i=j) { for (j=i+1;j<=m && q[j].x==q[i].x && q[j].y==q[i].y;j++); ans-=(long long)(j-i)*(j-i-1)/2; } long long b=(long long)m*(m-1)/2,Gcd=gcd(ans,b); printf("%lld/%lld\n",ans/Gcd,b/Gcd); return 0; }
相关文章推荐
- MyBatis学习总结(七)——Mybatis缓存
- LeetCode之Binary Tree Postorder Traversal
- Java中的Enum的使用与分析
- 接收对 http://192.168.1.18:8001/ObtainData/Service 的 HTTP 响应时发生错误。这可能是由于服务终结点绑定未使用 HTTP 协议造成的。这还可能是由于服务器中止了 HTTP 请求上下文(可能由于服务关闭)所致。
- 初来咋到,请多指教
- canvas动态的连线
- Android开发过程解决软键盘遮住EditText的问题
- css display属性
- appweb的开发步骤简介
- oracle 11g 按时间建分区表
- poj 1386 Play on Words(欧拉回路&&并查集)(中等)
- Linux时间子系统之五:低分辨率定时器的原理和实现
- python中**dict
- Java序列化
- MapReduce实现基本SQL操作的原理-join和group by,以及Dinstinct
- java注解annotation,自定义注解--shanchu
- 有关背包问题
- JavaScript实现文字跟随鼠标特效
- 获取servlet相关的域对象
- js开发技巧