感觉做这种题收获很大。

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. 2、java语言基础

    1.关键字 被Java语言赋予特定含义的单词被称为关键字关键字都是小写的在Java开发工具中,针对关键字有特殊颜色的标记 2.标识符 Java标识符命名规则 ·标识符是由,数字,字母,下划线和美元符号 ...

  2. C#里面中将字符串转为变量名

    public partial class Form1 : Form { string str = "spp"; public string spp = "very goo ...

  3. SVM支持向量机的基本原理

    SVM支持向量机的基本原理 对于很多分类问题,例如最简单的,一个平面上的两类不同的点,如何将它用一条直线分开?在平面上我们可能无法实现,但是如果通过某种映射,将这些点映射到其它空间(比如说球面上等), ...

  4. linux——vi和vim的区别

    vi 和vim 的区别   它们都是多模式编辑器,不同的是vim 是vi的升级版本,它不仅兼容vi的所有指令,而且还有一些新的特性在里面. vim的这些优势主要体现在以下几个方面:1.多级撤消我们知道 ...

  5. PHP对象1: 创建对象与 $this

    <?php class perl{ public $name; function __construct($name){ echo '一个对象造好了<br/>'; $this-> ...

  6. django【ORM】 通过外键字段找对应类

    两个方法其实是一种,用哪个都行,看实例:   方法一: 从list_filter中的字符串,找到model对象的字段,然后得到这个外键对应的类 循环,把list_filter中对应的类所有对象 方法二 ...

  7. 64_s1

    SAASound-3.2-17.fc26.i686.rpm 13-Feb-2017 22:13 27650 SAASound-3.2-17.fc26.x86_64.rpm 13-Feb-2017 23 ...

  8. mac 上使用octave的plot错误的解决办法

    在mac10.10上使用octave的时候,键入 plot(x, y)的时候会出现如下错误: ^ line : unknown or ambiguous terminal type; type jus ...

  9. 大数据系列之Kafka安装

    先简单说下安装kafka的流程..(可配置多个zookeeper,这篇文只说一个zookeeper场景) 1.环境配置:jdk1.7+ (LZ用的是jdk1.8) 2.资料准备:下载 kafka_2. ...

  10. hdu 2852 KiKi's K-Number (线段树)

    版权声明:本文为博主原创文章,未经博主允许不得转载. hdu 2852 题意: 一个容器,三种操作: (1) 加入一个数 e (2) 删除一个数 e,如果不存在则输出 No Elment! (3) 查 ...