例一:不带修改
Count on a tree II
Time Limit: 1207MS   Memory Limit: 1572864KB   64bit IO Format: %lld & %llu

Submit Status

Description

You are given a tree with N nodes. The tree nodes are numbered from 1 to N. Each node has an integer weight.

We will ask you to perform the following operation:

  • u v : ask for how many different integers that represent the weight of nodes there are on the path from u to v.

Input

In the first line there are two integers N and M. (N <= 40000, M <= 100000)

In the second line there are N integers. The i-th integer denotes the weight of the i-th node.

In the next N-1 lines, each line contains two integers u v, which describes an edge (uv).

In the next M lines, each line contains two integers u v, which means an operation asking for how many different integers that represent the weight of nodes there are on the path from u to v.

Output

For each operation, print its result.

Example

Input:
8 2
105 2 9 3 8 5 7 7
1 2
1 3
1 4
3 5
3 6
3 7
4 8
2 5
7 8
Output:
4
4

题目链接:http://acm.hust.edu.cn/vjudge/problem/27636

学习参考博客:http://blog.csdn.net/kuribohg/article/details/41458639

理解:我们要在树上使用莫队算法,首先需要将树上的装换成普通的序列,这里我们用到了dfs序。用in和out表示遍历是的时间顺序。然后把这个当作下标排序,分块。在处理转移问题是我们用inv来表示当前访问节点是否在当前区间里,然后根据上面的博客原理异或即可。处理lca的问题我们用倍增法求lca。

注意:w的权重需要离散化,lst存的是dfs序对应的节点(数组为N的两倍)。

AC:

#include<algorithm>
#include<iostream>
#include<cmath>
#include<map>
#include<string.h>
#include<cstring>
#include<vector>
#include<queue>
#include<stdio.h>
using namespace std;
#define ll  long long int
const int N=40008,M=100008;
int w[N],hd[N],to[N],dep[N],in[N],out[N],lst[N<<1],ans[M],pre[18][N],inv[N],v[N];
int num,uin,tot,n,m,res;
struct ss
{int id,v;bool operator < (const ss &a)const{return v<a.v;}
}ww[N];
struct G
{int v,next;
}mp[N<<1];
struct query
{int l,r,id,anc;bool operator <(const query &a) const{if(l/uin==a.l/uin) return r<a.r;else return l/uin<a.l/uin;}
}q[M];//查询
void add(int u,int v)//建树
{mp[++tot].next=hd[u];mp[tot].v=v;hd[u]=tot;
}
void dfs(int now,int h)//求dfs序,顺便保存公共祖先
{dep[now]=h;in[now]=++num;lst[num]=now;for(int k=hd[now];k;k=mp[k].next){if(!dep[mp[k].v]){dfs(mp[k].v,h+1);pre[0][mp[k].v]=now;}}out[now]=++num;lst[num]=now;
}
void lca_init()//pre[i][j]表示j节点的第2^(i)个父亲
{for (int i=1;i<=16;i++)for (int j=1;j<=n;j++)pre[i][j]=pre[i-1][pre[i-1][j]];
}
int lca(int u,int v)//倍增法求lca
{int d;if(dep[u]<dep[v]) swap(u,v);d=dep[u]-dep[v];for(int i=16;i>=0;i--){if(d&(1<<i)) u=pre[i][u];}//是u,v的深度相同if(u==v) return u;for(int i=16;i>=0;i--){if(pre[i][u]!=pre[i][v]){u=pre[i][u],v=pre[i][v];}}return pre[0][u];
}
void solve(int i)//转移状态
{if(inv[lst[i]]){v[w[lst[i]]]--;if(!v[w[lst[i]]]) res--;inv[lst[i]]=0;}else{if(!v[w[lst[i]]]) res++;v[w[lst[i]]]++;inv[lst[i]]=1;}
}
int main()
{int x,y;//freopen("in.txt","r",stdin);scanf("%d%d",&n,&m);for(int i=0;i<n;i++){scanf("%d",&ww[i].v);ww[i].id=i+1;}sort(ww,ww+n);int tmp=0;w[ww[0].id]=0;for(int i=1;i<n;i++){if(ww[i].v>ww[i-1].v) tmp++;w[ww[i].id]=tmp;}for(int i=1;i<n;i++){scanf("%d%d",&x,&y);add(x,y),add(y,x);}dfs(1,1);pre[0][1]=1;lca_init();for(int i=0;i<m;i++){scanf("%d%d",&x,&y);q[i].id=i;if(x==y) q[i].anc=-1;else{q[i].anc=lca(x,y);if(q[i].anc!=x&&q[i].anc!=y){q[i].l=min(out[x],out[y]);q[i].r=max(in[x],in[y]);}else{q[i].l=min(in[x],in[y]);q[i].r=max(in[x],in[y]);}}}uin=(int)sqrt(m*1.0);sort(q,q+m);int l,r;l=1; r=0;for(int i=0;i<m;i++){if(q[i].anc==-1){ans[q[i].id]=1;continue;}while(l<q[i].l){solve(l);l++;}while(l>q[i].l){l--;solve(l);}while(r>q[i].r){solve(r);r--;}while(r<q[i].r){r++;solve(r);}if(lst[q[i].l]==q[i].anc||lst[q[i].r]==q[i].anc){ans[q[i].id]=res;}else{solve(in[q[i].anc]);ans[q[i].id]=res;solve(in[q[i].anc]);}}for(int i=0;i<m ;i++){printf("%d\n",ans[i]);}
}

例二:带修改

Haruna’s Breakfast
Time Limit: 10000MS   Memory Limit: 131072KB   64bit IO Format: %lld & %llu

Submit Status

Description

Haruna每天都会给提督做早餐! 这天她发现早饭的食材被调皮的 Shimakaze放到了一棵

树上,每个结点都有一样食材,Shimakaze要考验一下她。
每个食材都有一个美味度,Shimakaze会进行两种操作:
1、修改某个结点的食材的美味度。
2、对于某条链,询问这条链的美味度集合中,最小的未出现的自然数是多少。即mex值。
请你帮帮Haruna吧。

Input

第一行包括两个整数n,m,代表树上的结点数(标号为1~n)和操作数。

第二行包括n个整数a1...an,代表每个结点的食材初始的美味度。
接下来n-1行,每行包括两个整数u,v,代表树上的一条边。
接下来m 行,每行包括三个整数
0 u x 代表将结点u的食材的美味度修改为 x。
1 u v 代表询问以u,v 为端点的链的mex值。

Output

对于每次询问,输出该链的mex值。

Sample Input

10 10
1 0 1 0 2 4 4 0 1 0
1 2
2 3
2 4
2 5
1 6
6 7
2 8
3 9
9 10
0 7 14
1 6 6
0 4 9
1 2 2
1 1 8
1 8 3
0 10 9
1 3 5
0 10 0
0 7 7

Sample Output

0
1
2
2
3

Hint

1<=n<=5*10^4

1<=m<=5*10^4
0<=ai<=10^9

解法:对于对点的权值存在修改,然后我们排序的时候增加一维,操作时间。对于询问区间时,我们可以先把点的权值转移到t的状态然后再跑一次普通的树上莫队。

注意:由于题目要求的是mex,我们只需要记录出现的权值即可。mex肯定在(0~n)之间,所以对于出现过大于n的权重我们可以跳过即可。ps:之前没发现这个,用map映射被一个lg卡到崩溃。。。。。。。

AC:

#include<iostream>
#include<string>
#include<stdio.h>
#include<string.h>
#include<vector>
#include<math.h>
#include<queue>
#include<map>
#include<set>
#include<algorithm>
using namespace std;
#define LL long long
#define INF 0x3f7f7f7f3f7f7f7f
const int maxn=100008;
const int K=16;
int hd[maxn],lst[maxn<<1],in[maxn],out[maxn],pre[20][maxn],dep[maxn],num,tot,unit,res;
int cc[maxn],uu[maxn],to[maxn],last[maxn],c[maxn],inv[maxn],vis[maxn],ans[maxn];
int v[maxn];
int n,m;
int mex()
{for(int i=0;;i++){if(!v[i]) return i;}
}
struct query
{int l,r,anc,id,ti;bool operator < (const query &b) const{if(l/unit==b.l/unit){return r==b.r? ti<b.ti:r<b.r;}else return l/unit<b.l/unit;}}q[maxn];
struct G
{int next,v;
}mp[maxn<<1];
void add(int u,int v)
{mp[++tot].v=v;mp[tot].next=hd[u];hd[u]=tot;
}
void dfs(int now,int h)
{dep[now]=h;in[now]=++num;lst[num]=now;for(int k=hd[now];k;k=mp[k].next){if(!dep[mp[k].v]){dfs(mp[k].v,h+1);pre[0][mp[k].v]=now;}}out[now]=++num;lst[num]=now;
}
void lca_init()
{for(int i=1;i<=K;i++){for(int j=1;j<=n;j++){pre[i][j]=pre[i-1][pre[i-1][j]];}}
}
int lca(int u,int v)
{if(dep[u]<dep[v]) swap(u,v);int d=dep[u]-dep[v];for(int i=K;i>=0;i--){if(d&(1<<i)){u=pre[i][u];}}if(u==v) return u;for(int i=K;i>=0;i--){if(pre[i][u]^pre[i][v]){u=pre[i][u];v=pre[i][v];}}return pre[0][u];
}
void solve(int i)//莫队转移
{if (inv[lst[i]]){inv[lst[i]]=0;if(c[lst[i]]>n) return ;v[c[lst[i]]]--;}else{inv[lst[i]]=1;if(c[lst[i]]>n) return ;v[c[lst[i]]]++;}
}
void chage(int t)//转移时间状态
{if(vis[t]){vis[t]=0;if(inv[uu[t]]&&c[uu[t]]<n){v[c[uu[t]]]--;}c[uu[t]]=last[t];if(inv[uu[t]]&&c[uu[t]]<n){v[c[uu[t]]]++;}}else{vis[t]=1;if(inv[uu[t]]&&c[uu[t]]<n){v[c[uu[t]]]--;}c[uu[t]]=to[t];if(inv[uu[t]]&&c[uu[t]]<n){v[c[uu[t]]]++;}}
}
struct FastIO
{static const int S = 1310720;int wpos;char wbuf[S];FastIO() : wpos(0) {}inline int xchar(){static char buf[S];static int len = 0, pos = 0;if(pos == len)pos = 0, len = fread(buf, 1, S, stdin);if(pos == len) return -1;return buf[pos ++];}inline int xuint(){int c = xchar(), x = 0;while(c <= 32){c = xchar();}for(; '0' <= c && c <= '9'; c = xchar()) x = x * 10 + c - '0';return x;}inline void wchar(int x){if(wpos == S) fwrite(wbuf, 1, S, stdout), wpos = 0;wbuf[wpos ++] = x;}inline void wint(int x){if(x < 0) wchar('-'), x = -x;char s[24];int n = 0;while(x || !n) s[n ++] = '0' + x % 10, x /= 10;while(n--) wchar(s[n]);}~FastIO(){if(wpos) fwrite(wbuf, 1, wpos, stdout), wpos = 0;}
} io;//输入外挂
int main()
{//freopen("in.txt","r",stdin);n=io.xuint();m=io.xuint();int u,v,len1,pos1,time;len1=time=0;for(int i=1;i<=n;i++){c[i]=io.xuint();cc[i]=c[i];}for(int i=1;i<n;i++){u=io.xuint();v=io.xuint();add(u,v);add(v,u);}pre[0][1]=1;dfs(1,1);lca_init();unit=(int)sqrt(num*1.0);for(int i=0;i<m;i++){pos1=io.xuint();u=io.xuint();v=io.xuint();if(pos1==1){q[len1].anc=lca(u,v);q[len1].ti=time;q[len1].id=len1;q[len1].anc=lca(u,v);if (q[len1].anc!=u&&q[len1].anc!=v){q[len1].l=min(out[u],out[v]);q[len1].r=max(in[u],in[v]);}else{q[len1].l=min(in[u],in[v]);q[len1].r=max(in[u],in[v]);}len1++;}else{uu[++time]=u;to[time]=v;last[time]=cc[u];cc[u]=v;}}sort(q,q+len1);int l=1,r=0,t=0;for(int i=0;i<len1;i++){while(t<q[i].ti) chage(t+1),t++;while(t>q[i].ti)chage(t),t--;for (;l<q[i].l;l++) solve(l);for (;q[i].l<l;l--)  solve(l-1);for (;r<q[i].r;r++) solve(r+1);for (;q[i].r<r;r--) solve(r);if (lst[q[i].l]==q[i].anc||lst[q[i].r]==q[i].anc)ans[q[i].id]=mex();else{solve(in[q[i].anc]);ans[q[i].id]=mex();solve(in[q[i].anc]);}}for(int i=0;i<len1;i++){io.wint(ans[i]);io.wchar('\n');}
}

莫队算法二(树上莫队cot2,Haruna’s Breakfast)相关推荐

  1. 莫队算法 (普通莫队、带修莫队、树上莫队)

    莫队算法 主要基于分块的思想 用结构体记录询问的左右端点及询问编号 (这是一个离线算法) 通过排序优化指针扫描顺序优化时间复杂度 . 1.普通莫队 例题:SP3267 DQUERY - D-query ...

  2. 莫队算法(普通莫队、带修莫队、树上莫队、不删除莫队)学习笔记【理解+套路/核心代码+例题及题解】

    一.理解 我的理解就是巧妙的暴力,利用双指针以及分块思想,巧妙的移动双指针,时间复杂度可以达到O(NlogN). 强推博客:写的又好又全.链接 二.套路 1.普通莫队 [1]核心代码 bool cmp ...

  3. 分治 —— 莫队算法 —— 带修莫队

    [概述] 普通莫队由于强制离线是不能修改的,但对于强制在线的题,可以在普通莫队的基础上强行加上一维时间轴 time,表示这次操作的时间,即在每个询问前已经完成了多少次修改. 简单来说,就是将询问 [l ...

  4. 【莫队/树上莫队/回滚莫队】原理详解及例题:小B的询问(普通莫队),Count on a tree II(树上莫队),kangaroos(回滚莫队)

    文章目录 问题引入 介绍莫队算法及其实现过程 时间复杂度 莫队算法适用范围 莫队奇偶优化 普通莫队:小B的询问 树上莫队:SP10707 COT2 - Count on a tree II 回滚莫队: ...

  5. 离线区间的神奇——莫队算法

    离线区间的神奇--莫队算法 前言 一.什么是莫队算法? 二.例题分析: 1.相关例题 题目描述 输入格式 输出格式 简单分析: 三.莫队算法思想: 那么要怎么做(预处理):莫队算法优化的核心是**分块 ...

  6. hdu 5213(容斥原理+莫队算法)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5213 莫队算法是离线处理一类区间不修改查询类问题的算法.就是如果你知道了[L,R]的答案.你可以在O( ...

  7. 清橙A1206 小Z的袜子(莫队算法)

    A1206. 小Z的袜子 时间限制:1.0s   内存限制:512.0MB   总提交次数:744   AC次数:210   平均分:44.44 将本题分享到:        查看未格式化的试题    ...

  8. 莫队算法 ( MO's algorithm )

    莫队算法是由清华大学神牛莫涛发明的一种处理区间问题的离线算法 算法核心是通过先将问询区间总长度平方分块.然后将所有的问询区间按照左端点所在的块编号排序.在同一块内的则按右端点升序 然后设置左右两个下标 ...

  9. [CSP-S模拟测试]:蔬菜(二维莫队)

    题目描述 小$C$在家中开垦了一块菜地,可以抽象成一个$r\times c$大小的矩形区域,菜地的每个位置都种着一种蔬菜.秋天到了,小$C$家的菜地丰收了. 小$C$拟定了$q$种采摘蔬菜的计划,计划 ...

最新文章

  1. MS SQL Server存储过程
  2. java List集合
  3. 多角度对比数据中心常见的三种走线方式
  4. 【Python】推荐10个好用到爆的Jupyter Notebook插件,让你效率飞起
  5. 蓝桥杯 子串分值 递推
  6. tesorflow 填充‘same’与‘valid’
  7. 工业相机硬汉!这款相机被NASA选择,全程记录毅力号登陆火星
  8. Hadoop系列之九:Hadoop集群伪分布式模式的实现详解
  9. setwindowpos怎么改变z序_Windows转Mac——操作习惯的改变!
  10. Android UI 自定义控件大全
  11. 你必须掌握的人生定律
  12. 服务器硬盘热插拔后告警,IBM硬盘所谓支持热插拔带来的问题
  13. SQL脚本得到Epicor客制化信息
  14. 从zookeeper官方文档系统学习zookeeper
  15. unity通过鼠标滑轮控制物体大小
  16. 【靶场补充】项目十二补充(shellshock原理)
  17. Python实现鸡群算法
  18. 无线鼠标 桌面服务器,你可能不知道 桌面总是乱糟糟的很可能是因为你没买对鼠标...
  19. Redis的清洁——定期删除+惰性删除+内存淘汰策略
  20. unity 雷电游戏

热门文章

  1. HZ服务器装系统速度变慢,360Hz刷新率有些什么厉害的地方?响应时间系统延迟测试...
  2. Cocos Creator游戏开发教程 学习笔记
  3. mysql 必知必会【沈剑——公众号架构师之路】
  4. 计算机毕业设计php+vue基于微信小程序的房屋租赁小程序
  5. 网红汉字手机全屏时钟APP下载
  6. linux系统升级python版本
  7. 【蘑菇街技术部年会】程序员与女神共舞,鼻血再次没止住。(文末内推)
  8. 货郎担问题(TSP问题)
  9. QQ\微信等聊天记录备份与恢复
  10. 空间机械臂Matlab/Simulink仿真程序自由漂浮空间机械臂(双臂)轨迹跟踪控制matlab仿真程序