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】苹果树 树上莫队(树分块+离线莫队+鬼畜的压行)的更多相关文章

  1. 【BZOJ】4129: Haruna’s Breakfast 树分块+带修改莫队算法

    [题意]给定n个节点的树,每个节点有一个数字ai,m次操作:修改一个节点的数字,或询问一条树链的数字集合的mex值.n,m<=5*10^4,0<=ai<=10^9. [算法]树分块+ ...

  2. 【BZOJ】3052: [wc2013]糖果公园 树分块+带修改莫队算法

    [题目]#58. [WC2013]糖果公园 [题意]给定n个点的树,m种糖果,每个点有糖果ci.给定n个数wi和m个数vi,第i颗糖果第j次品尝的价值是v(i)*w(j).q次询问一条链上每个点价值的 ...

  3. 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 ...

  4. [BZOJ 1086] [SCOI2005] 王室联邦 【树分块】

    题目链接:BZOJ - 1086 题目分析 这道题要求给树分块,使得每一块的大小在 [B, 3B] 之间,并且可以通过一个块外的节点(块根)使得整个块联通. 那么我们使用一种 DFS,维护一个栈,DF ...

  5. luogu P4887 模板 莫队二次离线 莫队 离线

    LINK:模板莫队二次离线 很早以前学的知识点 不过 很久了忘了. 考虑暴力 :每次莫队更新的时候 尝试更新一个点到一个区间的答案 可以枚举二进制下位数为k的数字 看一下区间内的这种数字有多少个. 不 ...

  6. BZOJ.3757.苹果树(树上莫队)

    题面链接 /* 代码正确性不保证..(不过交了SPOJ没WA T了最后一个点) 在DFS序做莫队 当一个点不是另一个点的LCA时,需要加上它们LCA的贡献 */ #include <cmath& ...

  7. BZOJ 1878 SDOI2009 HH的项链 树状数组/莫队算法

    题目大意:给定一个序列.求一个区间内有多少个不同的数 正解是树状数组 将全部区间依照左端点排序 然后每次仅仅统计左端点開始的每种颜色的第一个数即可了 用树状数组维护 我写的是莫队算法 莫队明显能搞 m ...

  8. BZOJ 3166 set+可持久化trie树(OR 莫队)

    思路: 1.找次大值 我们不妨设当前点是次大的 那这段区间为 左边第二个比它大的点的坐标+1 和右边第二个比它大的点的坐标-1 2.用可持久化trie树找异或最大值 也可以用莫队 //By Siriu ...

  9. 【BZOJ 3529】 [Sdoi2014]数表 (莫比乌斯+分块+离线+树状数组)

    3529: [Sdoi2014]数表 Description 有一张N×m的数表,其第i行第j列(1 < =i < =礼,1 < =j < =m)的数值为能同时整除i和j的所有 ...

随机推荐

  1. 转:Git 求生手册 - 第三章分支工作

    from:http://newbranch.cn/zhi-zuo-fen-zhi-lai-gong-zuo-git-gh-pages-branching/ 来自:片段 实战 说了这么一大堆分支的东西. ...

  2. sublime3 常用插件

    1,emmet,html代码自动补全插件 2,jsFormat js格式化插件 3,HTMLBeautify 格式化html插件 4,autoPrefix css3自动补全前缀 5,SublimeCo ...

  3. Maven 常用命令, 备忘

    Maven在现在的Java项目中有非常重要的地位, Maven已经不是Ant这样仅仅用于构建, 首先, 它是一个构建工具, 把源代码编译并打包成可发布应用的构件工具其次, 它是一个依赖管理工具, 集中 ...

  4. 使用ViewBag传送数据从控制器至视图

    前一篇<ASP.NET MVC读取XML并使用ViewData显示>http://www.cnblogs.com/insus/p/4308740.html 中,在控制器中使用了ViewDa ...

  5. 招聘 微软全球技术支持中心 sql server组

    微软亚太区全球技术支持中心(APGC CSS)是微软为个人用户.开发者.IT 专业人员到合作伙伴和企业级合作伙伴提供全方位.多元化的服务和技术支持的部门.一个优秀的SQL Server技术支持工程师应 ...

  6. NET Core HTTP 管道

    ASP.NET Core HTTP 管道中的那些事儿   前言 马上2016年就要过去了,时间可是真快啊. 上次写完 Identity 系列之后,反响还不错,所以本来打算写一个 ASP.NET Cor ...

  7. NET WebApi OWIN 实现 OAuth 2.0

    NET WebApi OWIN 实现 OAuth 2.0 OAuth(开放授权)是一个开放标准,允许用户让第三方应用访问该用户在某一网站上存储的私密的资源(如照片,视频,联系人列表),而无需将用户名和 ...

  8. nfs 三个参数权限

    遇到nfs客户端不可写的情况.  有延迟啊啊啊..  等1min左右就可以写了. 挂载参数: cat /var/lib/nfs/etab -->server cat /proc/mounts   ...

  9. Linux 网络编程详解七(并发僵尸进程处理)

    在上一篇程序框架中,解决了子进程退出,父进程继续存在的功能,但是多条客户端连接如果同一时间并行退出,导致服务器端多个子进程同一时间全部退出,而SIGCHLD是不可靠信号,同时来多条信号可能无法处理,导 ...

  10. 程序猿看小说还要去找TXT?自己动手爬一个TXT才是正确的打开方式

    前言 在贴吧看了个小说追了几天被删帖了,于是自己找书名,打算下载下来看,结果要么是需要充值,要么不提供下载.作为一个猿类,怎么能忍. 好在小说网站多入牛毛,有的采用js加载文字来防采集,有的用css图 ...