bzoj 3772

 

感觉做这种题收获很大。

1、DFS序(广义上)除了用于静态子树操作,也可以用来做点到根的路上某些信息的统计(如点到根的路径上标记了多少个点),如果在加上lca,就可以支持路径的信息查询。

2、树上的可持久化线段树,如果每个节点要维护一个线段树,并且该线段树支持加减操作,那么通过可持久化+lca,搞定一条路径上的线段树的和(当然不仅局限于线段树)。

3、一条树上的路径覆盖另一条路径 <=> 后者的两个端点在前者的路径上。

 

题解看PoPoQQQ的博客:

http://blog.csdn.net/popoqqq/article/details/43122821

如果不清楚就看看代码。

 

  1 /**************************************************************
  2     Problem: 3772
  3     User: idy002
  4     Language: C++
  5     Result: Accepted
  6     Time:5824 ms
  7     Memory:65180 kb
  8 ****************************************************************/
  9  
 10 #include <cstdio>
 11 #include <vector>
 12 #define N 100010
 13 #define S 4000000
 14 #define P 16
 15 using namespace std;
 16  
 17 typedef long long dnt;
 18  
 19 struct Node {
 20     int s;
 21     Node *ls, *rs;
 22 }pool[S], *tail=pool, *root[N], *null=pool;
 23 struct Qry {
 24     int u, v;
 25     Qry(){}
 26     Qry( int u, int v ):u(u),v(v){}
 27 };
 28  
 29 int n, m;
 30 int head[N], dest[N+N], next[N+N], ntot;
 31 int in[N], out[N], idc;
 32 int anc[N][P+1], dep[N];
 33 vector<int> vc[N];
 34 Qry qry[N];
 35  
 36 void insert( int u, int v ) {
 37     ntot++;
 38     next[ntot] = head[u];
 39     dest[ntot] = v;
 40     head[u] = ntot;
 41 }
 42 Node *modify( Node *nd, int lf, int rg, int pos, int delta ) {
 43     Node *rt = ++tail;
 44     if( lf==rg ) {
 45         rt->s = nd->s + delta;
 46         return rt;
 47     }
 48     int mid=(lf+rg)>>1;
 49     if( pos<=mid ) {
 50         rt->ls = modify( nd->ls, lf, mid, pos, delta );
 51         rt->rs = nd->rs;
 52     } else {
 53         rt->ls = nd->ls;
 54         rt->rs = modify( nd->rs, mid+1, rg, pos, delta );
 55     }
 56     rt->s = rt->ls->s + rt->rs->s;
 57     return rt;
 58 }
 59 int query( Node *nd, int lf, int rg, int L, int R ) {
 60     if( L<=lf && rg<=R ) return nd->s;
 61     int mid=(lf+rg)>>1;
 62     int rt = 0;
 63     if( L<=mid ) rt += query( nd->ls, lf, mid, L, R );
 64     if( R>mid ) rt += query( nd->rs, mid+1, rg, L, R );
 65     return rt;
 66 }
 67 int query( Node *p1, Node *p2, Node *p3, Node *p4, int L, int R ) {
 68     /*  (p1+p2-p3-p4) as one tree  */
 69     int s1, s2, s3, s4;
 70     s1 = query(p1,1,idc,L,R);
 71     s2 = query(p2,1,idc,L,R);
 72     s3 = query(p3,1,idc,L,R);
 73     s4 = query(p4,1,idc,L,R);
 74     return s1+s2-s3-s4;
 75 }
 76 void dfs1( int u ) {
 77     in[u] = ++idc;
 78     for( int p=1; p<=P; p++ )
 79         anc[u][p] = anc[anc[u][p-1]][p-1];
 80     for( int t=head[u]; t; t=next[t] ) {
 81         int v=dest[t];
 82         if( v==anc[u][0] ) continue;
 83         anc[v][0] = u;
 84         dep[v] = dep[u]+1;
 85         dfs1(v);
 86     }
 87     out[u] = ++idc;
 88 }
 89 void dfs2( int u ) {
 90     root[u] = root[anc[u][0]];
 91     for( int t=0; t<vc[u].size(); t++ ) {
 92         int v=vc[u][t];
 93         root[u] = modify( root[u], 1, idc, in[v], +1 );
 94         root[u] = modify( root[u], 1, idc, out[v], -1 );
 95     }
 96     for( int t=head[u]; t; t=next[t] ) {
 97         int v=dest[t];
 98         if( v==anc[u][0] ) continue;
 99         dfs2(v);
100     }
101 }
102 int lca( int u, int v ) {
103     if( dep[u]<dep[v] ) swap(u,v);
104     int t=dep[u]-dep[v];
105     for( int p=0; t; t>>=1,p++ )
106         if( t&1 ) u=anc[u][p];
107     if( u==v ) return u;
108     for( int p=P; p>=0 && anc[u][0]!=anc[v][0]; p-- )
109         if( anc[u][p]!=anc[v][p] )
110             u=anc[u][p], v=anc[v][p];
111     return anc[u][0];
112 }
113 dnt gcd( dnt a, dnt b ) {
114     return b ? gcd(b,a%b) : a;
115 }
116 int main() {
117     scanf( "%d%d", &n, &m );
118     for( int i=1,u,v; i<n; i++ ) {
119         scanf( "%d%d", &u, &v );
120         insert( u, v );
121         insert( v, u );
122     }
123     for( int i=1,u,v; i<=m; i++ ) {
124         scanf( "%d%d", &u, &v );
125         vc[u].push_back(v);
126         qry[i] = Qry(u,v);
127     }
128  
129     anc[1][0] = 0;
130     dep[1] = 1;
131     dfs1(1);
132  
133     null->ls = null->rs = null;
134     root[0] = null;
135     dfs2(1);
136  
137     dnt cnt = 0, tot = 0, cd = 0;
138     for( int i=1; i<=m; i++ ) {
139         int u=qry[i].u, v=qry[i].v, ca=lca(u,v);
140         cnt += query( root[u], root[v], root[ca], root[anc[ca][0]], in[ca], in[u] );
141         cnt += query( root[u], root[v], root[ca], root[anc[ca][0]], in[ca], in[v] );
142         cnt -= query( root[u], root[v], root[ca], root[anc[ca][0]], in[ca], in[ca] );
143         cnt --;
144     }
145     tot = (dnt)m*(m-1)/2;
146     cd = gcd(tot,cnt);
147     printf( "%lld/%lld\n", cnt/cd, tot/cd );
148 }
View Code

 

posted @ 2015-04-01 20:40  idy002  阅读(227)  评论(0编辑  收藏  举报