bzoj 3772
感觉做这种题收获很大。
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的更多相关文章
- bzoj 3772 :精神污染 线段树+打标记 or 主席树
3772: 精神污染 Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 315 Solved: 87[Submit][Status][Discuss] D ...
- BZOJ 3772: 精神污染 (dfs序+树状数组)
跟 BZOJ 4009: [HNOI2015]接水果一样- CODE #include <set> #include <queue> #include <cctype&g ...
- 【BZOJ 3772】精神污染 主席树+欧拉序
这道题的内存…………………真·精神污染……….. 这道题的思路很明了,我们就是要找每一个路径包含了多少其他路径那么就是找,有多少路径的左右端点都在这条路径上,对于每一条路径,我们随便选定一个端点作为第 ...
- bzoj 3772 精神污染 主席树+dfs序
精神污染 Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 637 Solved: 177[Submit][Status][Discuss] Descri ...
- BZOJ 3772: 精神污染(dfs序+主席树)
传送门 解题思路 比较神仙的一道题.首先计算答案时可以每条路径所包含的路径数,对于\(x,y\)这条路径,可以在\(x\)这处开个\(vector\)存\(y\),然后计算时只需要算这个路径上每个点的 ...
- BZOJ 2127: happiness [最小割]
2127: happiness Time Limit: 51 Sec Memory Limit: 259 MBSubmit: 1815 Solved: 878[Submit][Status][Di ...
- BZOJ 3275: Number
3275: Number Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 874 Solved: 371[Submit][Status][Discus ...
- BZOJ 2879: [Noi2012]美食节
2879: [Noi2012]美食节 Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 1834 Solved: 969[Submit][Status] ...
- bzoj 4610 Ceiling Functi
bzoj 4610 Ceiling Functi Description bzoj上的描述有问题 给出\(n\)个长度为\(k\)的数列,将每个数列构成一个二叉搜索树,问有多少颗形态不同的树. Inp ...
随机推荐
- html5手机Web单页应用实践--起点移动阅读
一开始以hybrid形式做了一个android的小说阅读客户端,叫4G阅读.而后由于业务需求,要迅速实现纯手机html5 版的,所以就直接在原先客户端内内嵌的网页进行改版,快速实现以后在优化的过程中发 ...
- python3学习笔记.3.条件控制与循环
1.条件控制 关键字 if.elif.else 一般形式如下: if 条件1: 结果1 elif 条件2: 结果2 else: 结果3 注意:条件后的:语句的缩进的是相同的 2.循环语句 关键字有 ...
- Test plan
Options for Test Strategy: 1. Regular test: all the planned test cases will be executed 2. Extented ...
- gunicorn之日志详细配置
gunicorn的日志配置 gunicorn的日志配置相关的常用参数有4个,分别是accesslog,access_log_format,errorlog,loglevel. accesslog:用户 ...
- Android的休眠与唤醒
Android 休眠(suspend),在一个打过android补丁的内核中,state_store()函数会走另外一条路,会进入到request_suspend_state()中,这个文件在earl ...
- scrapy shell 用法(慢慢更新...)
scrapy shell 命令 1.scrapy shell url #url指你所需要爬的网址 2.有些网址数据的爬取需要user-agent,scrapy shell中可以直接添加头文件, 第①种 ...
- 提高spring boot jpa性能(译)
Spring Data JPA为Spring应用程序提供了数据访问层的实现.这是一个非常方便的组件,因为它不会重新发明每个新应用程序的数据访问方式,因此您可以花更多时间来实现业务逻辑.使用Spring ...
- slf4j中的Logger 使用占位符{} 来传入参数记录日志信息
首先要导入 slf4j包中的2个类 import org.slf4j.Logger;import org.slf4j.LoggerFactory; 再定义如下 private final static ...
- java关键字(详解)
目录 1. 基本类型 1) boolean 布尔型 2) byte 字节型 3) char 字符型 4) double 双精度 5) float 浮点 6) int 整型 7) long 长整型 8) ...
- golang-goroutine和channel
goroutine 在go语言中,每一个并发的执行单元叫做一个goroutine 这里说到并发,所以先解释一下并发和并行的概念: 并发:逻辑上具备同时处理多个任务的能力 并行:物理上在同一时刻执行多个 ...