题目大意:给定一棵树和树上的m条路径,求这m条路径中任选两条不同的路径时其中一条包含另一条的概率是多少
这题还真是精神污染- -
首先一个显而易见的结论就是如果路径A包含于路径B 那么就有A的两端点在路径B上 这是个充要条件
于是我们对于每个A路径的两段点x和y,将x开一个vector,把y存进去
这样对于每个B路径 我们要找的就是B路径上的所有点在vector中有多少出边也在这条B路径上
有些拗口- -
那么我们可以维护树上主席树来确定B链对应的线段树
我们要确定的就是B链对应的线段树中有多少点在B链上
那么维护入栈出栈序就可以了
将每个点维护一个可持久化线段树 版本是父亲版本加上该节点的vector中所有元素在入栈出栈序上的位置
由于是入栈出栈序 因此入栈为1 出栈为-1
由于入栈出栈序只能查询一个节点指向根的一条链 因此我们将[x,y]这条链拆成[x,lca]和[lca,y]两段
这其中由于lca被算了两次 因此还要减掉[lca,lca] 就可以了
注意自己对自己的影响不计入答案
- -卡内存差评
#include <vector> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define M 100100 using namespace std; struct Segtree{ Segtree *ls,*rs; int val; void* operator new (size_t,Segtree *_,Segtree *__,int ___) { static Segtree mempool[3804000],*C=mempool; C->ls=_; C->rs=__; C->val=___; return C++; } Segtree* Insert(int x,int y,int pos,int val) { int mid=x+y>>1; if(x==y) return new (0x0,0x0,this->val+val) Segtree; if(pos<=mid) return new (ls->Insert(x,mid,pos,val),rs,this->val+val) Segtree; else return new (ls,rs->Insert(mid+1,y,pos,val),this->val+val) Segtree; } friend int Get_Ans(Segtree *p1,Segtree *p2,Segtree *p3,Segtree *p4,int x,int y,int l,int r) { int mid=x+y>>1; if(x==l&&y==r) return p1->val+p2->val-p3->val-p4->val; if(r<=mid) return Get_Ans(p1->ls,p2->ls,p3->ls,p4->ls,x,mid,l,r); if(l>mid) return Get_Ans(p1->rs,p2->rs,p3->rs,p4->rs,mid+1,y,l,r); return Get_Ans(p1->ls,p2->ls,p3->ls,p4->ls,x,mid,l,mid) + Get_Ans(p1->rs,p2->rs,p3->rs,p4->rs,mid+1,y,mid+1,r); } }*tree[M]; struct Query{ int x,y; bool operator < (const Query &q) const { if(x!=q.x) return x<q.x; return y<q.y; } bool operator == (const Query &q) const { return x==q.x && y==q.y; } }queries[M]; struct abcd{ int to,next; }table[M<<1]; int head[M],tot; int n,m; int fa[M],dpt[M],ancestor[M][18]; int get_in[M],get_out[M]; vector<int> a[M]; long long A,B; void Add(int x,int y) { table[++tot].to=y; table[tot].next=head[x]; head[x]=tot; } void DFS1(int x) { static int cnt; int i; dpt[x]=dpt[fa[x]]+1; get_in[x]=++cnt; for(i=head[x];i;i=table[i].next) if(table[i].to!=fa[x]) { fa[table[i].to]=x; ancestor[table[i].to][0]=x; DFS1(table[i].to); } get_out[x]=++cnt; } void DFS2(int x) { int i; vector<int>::iterator it; tree[x]=tree[fa[x]]; for(it=a[x].begin();it!=a[x].end();it++) { tree[x]=tree[x]->Insert(1,n<<1,get_in[*it],1); tree[x]=tree[x]->Insert(1,n<<1,get_out[*it],-1); } for(i=head[x];i;i=table[i].next) if(table[i].to!=fa[x]) DFS2(table[i].to); } int LCA(int x,int y) { int j; if(dpt[x]<dpt[y]) swap(x,y); for(j=17;~j;j--) if(dpt[ancestor[x][j]]>=dpt[y]) x=ancestor[x][j]; if(x==y) return x; for(j=17;~j;j--) if(ancestor[x][j]!=ancestor[y][j]) x=ancestor[x][j],y=ancestor[y][j]; return fa[x]; } int main() { //freopen("3772.in","r",stdin); //freopen("3772.out","w",stdout); int i,j,x,y; cin>>n>>m; for(i=1;i<n;i++) scanf("%d%d",&x,&y),Add(x,y),Add(y,x); for(i=1;i<=m;i++) { scanf("%d%d",&x,&y); a[x].push_back(y); queries[i].x=x; queries[i].y=y; } tree[0]=new (0x0,0x0,0) Segtree; tree[0]->ls=tree[0]->rs=tree[0]; DFS1(1); DFS2(1); for(j=1;j<=17;j++) for(i=1;i<=n;i++) ancestor[i][j]=ancestor[ancestor[i][j-1]][j-1]; for(i=1;i<=m;i++) { x=queries[i].x; y=queries[i].y; int lca=LCA(x,y); A+=Get_Ans(tree[x],tree[y],tree[lca],tree[fa[lca]],1,n<<1,get_in[lca],get_in[x]); A+=Get_Ans(tree[x],tree[y],tree[lca],tree[fa[lca]],1,n<<1,get_in[lca],get_in[y]); A-=Get_Ans(tree[x],tree[y],tree[lca],tree[fa[lca]],1,n<<1,get_in[lca],get_in[lca]); A--; } sort(queries+1,queries+m+1); for(i=1;i<=m;i=j) { for(j=i+1;j<=m&&queries[i]==queries[j];j++); A-=(long long)(j-i)*(j-i-1)>>1; } B=(long long)m*(m-1)>>1; long long gcd=__gcd(A,B); A/=gcd;B/=gcd; cout<<A<<'/'<<B<<endl; return 0; }