感觉做这种题收获很大。

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

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

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

题解看PoPoQQQ的博客:

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

如果不清楚就看看代码。

 /**************************************************************
Problem: 3772
User: idy002
Language: C++
Result: Accepted
Time:5824 ms
Memory:65180 kb
****************************************************************/ #include <cstdio>
#include <vector>
#define N 100010
#define S 4000000
#define P 16
using namespace std; typedef long long dnt; struct Node {
int s;
Node *ls, *rs;
}pool[S], *tail=pool, *root[N], *null=pool;
struct Qry {
int u, v;
Qry(){}
Qry( int u, int v ):u(u),v(v){}
}; int n, m;
int head[N], dest[N+N], next[N+N], ntot;
int in[N], out[N], idc;
int anc[N][P+], dep[N];
vector<int> vc[N];
Qry qry[N]; void insert( int u, int v ) {
ntot++;
next[ntot] = head[u];
dest[ntot] = v;
head[u] = ntot;
}
Node *modify( Node *nd, int lf, int rg, int pos, int delta ) {
Node *rt = ++tail;
if( lf==rg ) {
rt->s = nd->s + delta;
return rt;
}
int mid=(lf+rg)>>;
if( pos<=mid ) {
rt->ls = modify( nd->ls, lf, mid, pos, delta );
rt->rs = nd->rs;
} else {
rt->ls = nd->ls;
rt->rs = modify( nd->rs, mid+, rg, pos, delta );
}
rt->s = rt->ls->s + rt->rs->s;
return rt;
}
int query( Node *nd, int lf, int rg, int L, int R ) {
if( L<=lf && rg<=R ) return nd->s;
int mid=(lf+rg)>>;
int rt = ;
if( L<=mid ) rt += query( nd->ls, lf, mid, L, R );
if( R>mid ) rt += query( nd->rs, mid+, rg, L, R );
return rt;
}
int query( Node *p1, Node *p2, Node *p3, Node *p4, int L, int R ) {
/* (p1+p2-p3-p4) as one tree */
int s1, s2, s3, s4;
s1 = query(p1,,idc,L,R);
s2 = query(p2,,idc,L,R);
s3 = query(p3,,idc,L,R);
s4 = query(p4,,idc,L,R);
return s1+s2-s3-s4;
}
void dfs1( int u ) {
in[u] = ++idc;
for( int p=; p<=P; p++ )
anc[u][p] = anc[anc[u][p-]][p-];
for( int t=head[u]; t; t=next[t] ) {
int v=dest[t];
if( v==anc[u][] ) continue;
anc[v][] = u;
dep[v] = dep[u]+;
dfs1(v);
}
out[u] = ++idc;
}
void dfs2( int u ) {
root[u] = root[anc[u][]];
for( int t=; t<vc[u].size(); t++ ) {
int v=vc[u][t];
root[u] = modify( root[u], , idc, in[v], + );
root[u] = modify( root[u], , idc, out[v], - );
}
for( int t=head[u]; t; t=next[t] ) {
int v=dest[t];
if( v==anc[u][] ) continue;
dfs2(v);
}
}
int lca( int u, int v ) {
if( dep[u]<dep[v] ) swap(u,v);
int t=dep[u]-dep[v];
for( int p=; t; t>>=,p++ )
if( t& ) u=anc[u][p];
if( u==v ) return u;
for( int p=P; p>= && anc[u][]!=anc[v][]; p-- )
if( anc[u][p]!=anc[v][p] )
u=anc[u][p], v=anc[v][p];
return anc[u][];
}
dnt gcd( dnt a, dnt b ) {
return b ? gcd(b,a%b) : a;
}
int main() {
scanf( "%d%d", &n, &m );
for( int i=,u,v; i<n; i++ ) {
scanf( "%d%d", &u, &v );
insert( u, v );
insert( v, u );
}
for( int i=,u,v; i<=m; i++ ) {
scanf( "%d%d", &u, &v );
vc[u].push_back(v);
qry[i] = Qry(u,v);
} anc[][] = ;
dep[] = ;
dfs1(); null->ls = null->rs = null;
root[] = null;
dfs2(); dnt cnt = , tot = , cd = ;
for( int i=; i<=m; i++ ) {
int u=qry[i].u, v=qry[i].v, ca=lca(u,v);
cnt += query( root[u], root[v], root[ca], root[anc[ca][]], in[ca], in[u] );
cnt += query( root[u], root[v], root[ca], root[anc[ca][]], in[ca], in[v] );
cnt -= query( root[u], root[v], root[ca], root[anc[ca][]], in[ca], in[ca] );
cnt --;
}
tot = (dnt)m*(m-)/;
cd = gcd(tot,cnt);
printf( "%lld/%lld\n", cnt/cd, tot/cd );
}

bzoj 3772的更多相关文章

  1. bzoj 3772 :精神污染 线段树+打标记 or 主席树

    3772: 精神污染 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 315  Solved: 87[Submit][Status][Discuss] D ...

  2. BZOJ 3772: 精神污染 (dfs序+树状数组)

    跟 BZOJ 4009: [HNOI2015]接水果一样- CODE #include <set> #include <queue> #include <cctype&g ...

  3. 【BZOJ 3772】精神污染 主席树+欧拉序

    这道题的内存…………………真·精神污染……….. 这道题的思路很明了,我们就是要找每一个路径包含了多少其他路径那么就是找,有多少路径的左右端点都在这条路径上,对于每一条路径,我们随便选定一个端点作为第 ...

  4. bzoj 3772 精神污染 主席树+dfs序

    精神污染 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 637  Solved: 177[Submit][Status][Discuss] Descri ...

  5. BZOJ 3772: 精神污染(dfs序+主席树)

    传送门 解题思路 比较神仙的一道题.首先计算答案时可以每条路径所包含的路径数,对于\(x,y\)这条路径,可以在\(x\)这处开个\(vector\)存\(y\),然后计算时只需要算这个路径上每个点的 ...

  6. BZOJ 2127: happiness [最小割]

    2127: happiness Time Limit: 51 Sec  Memory Limit: 259 MBSubmit: 1815  Solved: 878[Submit][Status][Di ...

  7. BZOJ 3275: Number

    3275: Number Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 874  Solved: 371[Submit][Status][Discus ...

  8. BZOJ 2879: [Noi2012]美食节

    2879: [Noi2012]美食节 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 1834  Solved: 969[Submit][Status] ...

  9. bzoj 4610 Ceiling Functi

    bzoj 4610 Ceiling Functi Description bzoj上的描述有问题 给出\(n\)个长度为\(k\)的数列,将每个数列构成一个二叉搜索树,问有多少颗形态不同的树. Inp ...

随机推荐

  1. java.lang.NoClassDefFoundError: HttpServletRequest

    在eclipse里启动tomcat报错,错误日志:Caused by: java.lang.ClassNotFoundException: HttpServletRequest 在build path ...

  2. perl6正则 6: 大小写/空白/匹配所有符合

    这个 :g 只能写在外面 m:g /re/

  3. BBScan — 一个信息泄漏批量扫描脚本

    github:https://github.com/lijiejie/BBScan 有些朋友手上有几十万甚至上百万个域名,比如,乌云所有厂商的子域名. 如果把这30万个域名全部扔给wvs,APPsca ...

  4. elk系列3之通过json格式采集Nginx日志【转】

    转自 elk系列3之通过json格式采集Nginx日志 - 温柔易淡 - 博客园http://www.cnblogs.com/liaojiafa/p/6158245.html preface 公司采用 ...

  5. 省市区ajax联动

    function setCity1(){ var areaId1 = $('#areaId1').val(); var cityId1 = $('#cityId1'); var cityOpt = $ ...

  6. 在html页面中引入公共的头部和底部

    参考链接: http://www.cnblogs.com/jason-star/p/3345225.html http://blog.csdn.net/jsxzzliang/article/detai ...

  7. CentOS7 安装python库(numpy、scipy、matplotlib、scikit-learn、tensorflow)

    0.1准备工作 安装好CentOS7,配置好网络,确保网络畅通. 0.2root授权 首先:当前用户为kaid # vim /etc/sudoers 在root ALL=(ALL) ALL之后添加: ...

  8. C/C++——C语言跳出多重循环方法

    c语言的break语句只能跳出离它最近的一层循环,但是我们有时候需要跳出多层循环,以下有几种跳出多重循环的方法: 1. 使用goto ; i < MAX1; i++) { ; j < MA ...

  9. leetcode 之trap water(8)

    这题不太好想.可以先扫描找到最高的柱子,然后分别处理两边:记录下当前的局部最高点,如果当前点小于局部最高点,加上, 反则,替换当前点为局部最高点. int trapWater(int A[], int ...

  10. [实战]MVC5+EF6+MySql企业网盘实战(9)——编辑文件名

    写在前面 上篇文章实现了文件的下载,本篇文章将实现编辑文件名的功能. 系列文章 [EF]vs15+ef6+mysql code first方式 [实战]MVC5+EF6+MySql企业网盘实战(1) ...