【BZOJ 3735】苹果树 树上莫队(树分块+离线莫队+鬼畜的压行)
2016-05-09 UPD:学习了新的DFS序列分块,然后发现这个东西是战术核导弹?反正比下面的树分块不知道要快到哪里去了
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 50003;
const int M = 100003;
void read(int &k) {
k = 0; int fh = 1; char c = getchar();
for(; c < '0' || c > '9'; c = getchar())
if (c == '-') fh = -1;
for(; c >= '0' && c <= '9'; c = getchar())
k = (k << 1) + (k << 3) + c - '0';
k = k * fh;
} struct node {int nxt, to;} E[N << 1];
struct quest {int l, r, id, a, b, lca;} Q[M];
int f[N][17], pos[N << 1], L[N], R[N], color[N], cal[N];
int point[N], bel[N << 1], ans = 0, cnt = 0, n, m, A[M], deep[N];
bool vis[N]; void ins(int x, int y) {E[++cnt].nxt = point[x]; E[cnt].to = y; point[x] = cnt;}
void _(int x, int fa) {
pos[L[x] = ++cnt] = x;
for(int i = 1; i <= 16; ++i) {f[x][i] = f[f[x][i - 1]][i - 1]; if (f[x][i] == 0) break;}
for(int tmp = point[x]; tmp; tmp = E[tmp].nxt)
if (E[tmp].to != fa)
{deep[E[tmp].to] = deep[x] + 1; f[E[tmp].to][0] = x; _(E[tmp].to, x);}
pos[R[x] = ++cnt] = x;
}
int LCA(int x, int y) {
if (deep[x] < deep[y]) swap(x, y);
int d = deep[x] - deep[y];
for(int i = 0; i <= 16; ++i) if (d & (1 << i)) x = f[x][i];
if (x == y) return x;
for(int i = 16; i >= 0; --i) if (f[x][i] != f[y][i]) x = f[x][i], y = f[y][i];
return f[x][0];
}
bool cmp(quest A, quest B) {return bel[A.l] == bel[B.l] ? A.r < B.r : A.l < B.l;} int check(int a, int b) {return cal[a] && cal[b] && a != b;}
void update(int x) {
if (vis[x]) {if (!(--cal[color[x]])) --ans;}
else {if (!(cal[color[x]]++)) ++ans;}
vis[x] = !vis[x];
} int main() {
read(n); read(m);
for(int i = 1; i <= n; ++i) read(color[i]);
int lca, u, v, a, b;
for(int i = 1; i <= n; ++i) {
read(u); read(v);
ins(u, v); ins(v, u);
} cnt = 0;
_(1, 0);
for(int i = 1; i <= m; ++i) {
read(u); read(v); read(Q[i].a); read(Q[i].b); Q[i].id = i;
lca = LCA(u, v);
if (L[u] > L[v]) swap(u, v);
if (u != lca) {Q[i].l = R[u]; Q[i].r = L[v]; Q[i].lca = lca;}
else {Q[i].l = L[u]; Q[i].r = L[v]; Q[i].lca = 0;}
} int nn = n << 1, sq = sqrt(nn + 0.5), tmp = 0; cnt = 1;
for(int i = 1; i <= nn; ++i) {
bel[i] = tmp;
++cnt; if (cnt > sq) cnt = 1, ++tmp;
} sort(Q + 1, Q + m + 1, cmp); int l = 1, r = 0, tol, tor;
for(int i = 1; i <= m; ++i) {
tol = Q[i].l; tor = Q[i].r;
while (l < tol) update(pos[l++]);
while (l > tol) update(pos[--l]);
while (r < tor) update(pos[++r]);
while (r > tor) update(pos[r--]);
if (Q[i].lca) update(Q[i].lca);
A[Q[i].id] = ans - check(Q[i].a, Q[i].b);
if (Q[i].lca) update(Q[i].lca);
} for(int i = 1; i <= m; ++i)
printf("%d\n", A[i]); return 0;
}
学习了树上莫队,树分块后对讯问的$dfs序$排序,然后就可以滑动树链处理答案了。
关于树链的滑动,只需要特殊处理一下$LCA$就行了。
在这里一条树链保留下来给后面的链来转移的$now$的为这条树链上所有点除去$LCA$的颜色种数。因为如果要考虑$LCA$情况就太多了,不如单独考虑$LCA$。
转移后加上当前链的$LCA$进行统计,然后再去掉这个$LCA$更新一下$now$值给后面的链转移。
这都是我的理解,说的有点不清楚,具体请看vfk的题解 OTZ 虽然不是这道题,但是通过这篇博客学习树上莫队也是很好的。
PS:压行大法使代码看起来像一堵墙
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 50003
#define M 100003
#define read(x) x=getint()
using namespace std;
inline int getint() {int k = 0, fh = 1; char c = getchar(); for(; c < '0' || c > '9'; c = getchar()) if (c == '-') fh = -1; for(; c >= '0' && c <= '9'; c = getchar()) k = k * 10 + c - '0'; return k * fh;}
int n, m, color[N], cnt = 0, fa[N][16], deep[N], dfn[N << 1], now = 0;
int belong[N], cntblo = 0, sqrblo, top = 0, sta[N], ans[M], colsum[N], point[N];
short v[N];
struct Enode {int nxt, to;} E[N << 1];
struct node {int x, y, a, b, id;} q[M];
inline bool cmp(node A, node B) {return belong[A.x] == belong[B.x] ? dfn[A.y] < dfn[B.y] : dfn[A.x] < dfn[B.x];}
inline void ins(int x, int y) {E[++cnt].nxt = point[x]; E[cnt].to = y; point[x] = cnt;} inline void dfs(int x) {
dfn[x] = ++cnt;
int mark = top;
for(int i = 1; i <= 15; ++i)
fa[x][i] = fa[fa[x][i - 1]][i - 1];
for(int tmp = point[x]; tmp; tmp = E[tmp].nxt) {
int v = E[tmp].to;
if (v == fa[x][0]) continue;
deep[v] =deep[x] + 1;
fa[v][0] = x;
dfs(v);
if (top - mark >= sqrblo) {
++cntblo;
while (top != mark)
belong[sta[top--]] = cntblo;
}
}
sta[++top] = x;
} inline int LCA(int x, int y) {
if (deep[x] < deep[y])
swap(x, y);
int k = deep[x] - deep[y];
for(int j = 15; j >= 0; --j)
if (k & (1 << j))
x = fa[x][j];
if (x == y) return x;
for(int j = 15; j >= 0; --j)
if (fa[x][j] != fa[y][j])
x = fa[x][j], y = fa[y][j];
return fa[x][0];
} inline void pushup(int x) {
if (v[x]) {
--colsum[color[x]];
if (!colsum[color[x]])
--now;
} else {
if (!colsum[color[x]])
++now;
++colsum[color[x]];
}
v[x] ^= 1;
} inline void change(int x, int y) {
while (x != y) {
if (deep[x] < deep[y])
pushup(y), y = fa[y][0];
else
pushup(x), x = fa[x][0];
} //O)Z这个方法好神啊!!!我为什么想不到一个一个往上跳呢QAQ
} int main() {
read(n); read(m);
for(int i = 1; i <= n; ++i)
read(color[i]);
int u, v;
for(int i = 1; i <= n; ++i) {
read(u); read(v);
if (u == 0 || v == 0) continue;
ins(u, v);
ins(v, u);
}
sqrblo = ceil(sqrt(n));
cnt = 0;
dfs(1);
while (top)
belong[sta[top--]] = cntblo; for(int i = 1; i <= m; ++i) {
read(q[i].x); read(q[i].y); read(q[i].a); read(q[i].b); q[i].id = i;
if (dfn[q[i].x] > dfn[q[i].y])
swap(q[i].x, q[i].y);
} sort(q + 1, q + m + 1, cmp);
q[0].x = q[0].y = 1; for(int i = 1; i <= m; ++i) {
change(q[i - 1].x, q[i].x);
change(q[i - 1].y, q[i].y);
int lca = LCA(q[i].x, q[i].y);
pushup(lca);
ans[q[i].id] = now;
if (colsum[q[i].a] && colsum[q[i].b] && q[i].a != q[i].b)
--ans[q[i].id];
pushup(lca);
} for(int i = 1; i <= m; ++i)
printf("%d\n", ans[i]);
return 0;
}
$SDOI2016 Round1$之前做的最后一道题了,希望省选不要爆零啊$QAQ$
【BZOJ 3735】苹果树 树上莫队(树分块+离线莫队+鬼畜的压行)的更多相关文章
- 【BZOJ】4129: Haruna’s Breakfast 树分块+带修改莫队算法
[题意]给定n个节点的树,每个节点有一个数字ai,m次操作:修改一个节点的数字,或询问一条树链的数字集合的mex值.n,m<=5*10^4,0<=ai<=10^9. [算法]树分块+ ...
- 【BZOJ】3052: [wc2013]糖果公园 树分块+带修改莫队算法
[题目]#58. [WC2013]糖果公园 [题意]给定n个点的树,m种糖果,每个点有糖果ci.给定n个数wi和m个数vi,第i颗糖果第j次品尝的价值是v(i)*w(j).q次询问一条链上每个点价值的 ...
- BZOJ3236[Ahoi2013]作业——莫队+树状数组/莫队+分块
题目描述 输入 输出 样例输入 3 4 1 2 2 1 2 1 3 1 2 1 1 1 3 1 3 2 3 2 3 样例输出 2 2 1 1 3 2 2 1 提示 N=100000,M=1000000 ...
- [BZOJ 1086] [SCOI2005] 王室联邦 【树分块】
题目链接:BZOJ - 1086 题目分析 这道题要求给树分块,使得每一块的大小在 [B, 3B] 之间,并且可以通过一个块外的节点(块根)使得整个块联通. 那么我们使用一种 DFS,维护一个栈,DF ...
- luogu P4887 模板 莫队二次离线 莫队 离线
LINK:模板莫队二次离线 很早以前学的知识点 不过 很久了忘了. 考虑暴力 :每次莫队更新的时候 尝试更新一个点到一个区间的答案 可以枚举二进制下位数为k的数字 看一下区间内的这种数字有多少个. 不 ...
- BZOJ.3757.苹果树(树上莫队)
题面链接 /* 代码正确性不保证..(不过交了SPOJ没WA T了最后一个点) 在DFS序做莫队 当一个点不是另一个点的LCA时,需要加上它们LCA的贡献 */ #include <cmath& ...
- BZOJ 1878 SDOI2009 HH的项链 树状数组/莫队算法
题目大意:给定一个序列.求一个区间内有多少个不同的数 正解是树状数组 将全部区间依照左端点排序 然后每次仅仅统计左端点開始的每种颜色的第一个数即可了 用树状数组维护 我写的是莫队算法 莫队明显能搞 m ...
- BZOJ 3166 set+可持久化trie树(OR 莫队)
思路: 1.找次大值 我们不妨设当前点是次大的 那这段区间为 左边第二个比它大的点的坐标+1 和右边第二个比它大的点的坐标-1 2.用可持久化trie树找异或最大值 也可以用莫队 //By Siriu ...
- 【BZOJ 3529】 [Sdoi2014]数表 (莫比乌斯+分块+离线+树状数组)
3529: [Sdoi2014]数表 Description 有一张N×m的数表,其第i行第j列(1 < =i < =礼,1 < =j < =m)的数值为能同时整除i和j的所有 ...
随机推荐
- R语言学习笔记(二)
今天主要学习了两个统计学的基本概念:峰度和偏度,并且用R语言来描述. > vars<-c("mpg","hp","wt") &g ...
- jquery实现输入框聚焦,键盘上下键选择城市
在最近有个项目中 需要实现当文本框聚焦的时候,可以键盘上下键选择内容,按enter键的时候,把内容传到输入框中,如图所示: 实现代码如下: /** *输入框聚焦,键盘上下键选择城市 */ ;(func ...
- POJ1384Piggy-Bank[完全背包]
Piggy-Bank Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 10787 Accepted: 5258 Descr ...
- 第9章 用内核对象进行线程同步(3)_信号量(semaphore)、互斥对象(mutex)
9.5 信号量内核对象(Semaphore) (1)信号量的组成 ①计数器:该内核对象被使用的次数 ②最大资源数量:标识信号量可以控制的最大资源数量(带符号的32位) ③当前资源数量:标识当前可用资源 ...
- ubuntu14上安装ros教程
安装ROS 官方的安装教程地址 http://wiki.ros.org/cn/jade/Installation/Ubuntu 建议安装indigo版的 下面的教程是安装jade版的 配置Ubuntu ...
- Android 中布局设置导致的TextView不显示的问题
将TextView放入TableLayout中,设置TextView的Layout Witdh/Layout Height 为Wrap Content或其他大小,导致TextView内容无法显示,改为 ...
- PAT 1030. 完美数列(25)
给定一个正整数数列,和正整数p,设这个数列中的最大值是M,最小值是m,如果M <= m * p,则称这个数列是完美数列. 现在给定参数p和一些正整数,请你从中选择尽可能多的数构成一个完美数列. ...
- data:image/png;base64
大家可能注意到了,网页上有些图片的src或css背景图片的url后面跟了一大串字符,比如: data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAJ ...
- Codevs 1051 二叉树最大宽度和高度
1501 二叉树最大宽度和高度 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 白银 Silver 题目描述 Description 给出一个二叉树,输出它的最大宽 ...
- 【java】企业级分布式搜索平台Solr视频教程
课程背景为了满足高可用.可扩展并容错的分布式搜索引擎.Solr是一个高性能,采用Java5开发, 基于Lucene的全文搜索服务器.同时对其进行了扩展,提供了比Lucene更为丰富的查询语言,同时实现 ...