Time Limit: 20 Sec  Memory Limit: 400 MB

Description

  给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v),你需要回答u xor lastans和v这两个节点间有多少种不同的点权。其中lastans是上一个询问的答案,初始为0,即第一个询问的u是明文。

Input

  第一行两个整数N,M。
  第二行有N个整数,其中第i个整数表示点i的权值。
  后面N-1行每行两个整数(x,y),表示点x到点y有一条边。
  最后M行每行两个整数(u,v),表示一组询问。
  数据范围是N<=40000 M<=100000 点权在int范围内 

Output

  M行,表示每个询问的答案。

Sample 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
  3 8

Sample Output

  4
  4

Solution

  在线莫队(TLE):把树分成k块,每块选出一个点作为代表点,预处理出所有块的代表点到其他代表点路径上颜色种数和各种颜色的数量,每次询问找到两个询问点所在块,根据预处理出的信息可以在$O(\frac{n}{k})$时间内算出答案,复杂度$O(nk^{2}+\frac{qn}{k})$,适当调整k,总复杂度约为$O(n^{\frac{5}{3}})$,理论上很科学可是这题卡常……
  正解树分块+可持久化块状数组:把树分成k块,每块选出一个点作为代表点,预处理出各块代表点到其他所有点路径上的颜色种数,对于每个询问x,y,我们令所在块的代表点深度较大的为x,代表点为u,则我们利用预处理的信息可以知道u到y的路径上的答案,接下来我们把x到u的路径并入答案中,只要能支持$O(1)$询问一种颜色是否在u到y的路径上出现过即可$O(\frac{n}{k})$完成,我们预处理出每个点到根路径上各种颜色出现的最大深度,那么如果u到根和y到根出现一种颜色的最大深度大等于lca(u,y)的深度,那么这种颜色就在u到y的路径上出现过,暴力计算是$O(n^{2})$的,用可持久化块状数组我们就能实现$O(\sqrt{n})$从一个点的父亲那里复制数组,$O(\sqrt{n})$时间内修改一个元素,$O(1)$查询一个值,总复杂度约为$O(n\sqrt{n})$。

Code

在线莫队(TLE)

#include<cstdio>
#include<algorithm>
#include<map>
using namespace std;
inline int read()
{
int x,f=;char c;
while((c=getchar())<''||c>'')if(c=='-')f=;
for(x=c-'';(c=getchar())>=''&&c<='';)x=x*+c-'';
return f?x:-x;
}
#define MN 40000
#define K 713
#define LG 15
#define KS (MN/K)
map<int,int> mp;
struct edge{int nx,t;}e[MN*+];
int h[MN+],en,c[MN+],cnt,fa[LG+][MN+],d[MN+],s[MN+],ht[MN+],q[MN+],qr,b[MN+],p[KS+];
unsigned short ans[KS+][KS+],f[KS+][KS+][MN+];
bool u[KS+][KS+][MN+];
inline void ins(int x,int y)
{
e[++en]=(edge){h[x],y};h[x]=en;
e[++en]=(edge){h[y],x};h[y]=en;
}
void pre(int x)
{
for(int i=h[x];i;i=e[i].nx)if(e[i].t!=fa[][x])
{
fa[][e[i].t]=x;d[e[i].t]=d[x]+;
pre(e[i].t);
s[x]+=s[e[i].t];ht[x]=max(ht[x],ht[e[i].t]+);
}
if(++s[q[++qr]=x],(ht[x]=max(ht[x],))==K||x<)
{for(p[++cnt]=x;s[x]--;)b[q[qr--]]=cnt;ht[x]=s[x]=;}
}
inline void cal(int a,int b,int x)
{
(u[a][b][x]^=)?f[a][b][c[x]]++?:++ans[a][b]:
--f[a][b][c[x]]?:--ans[a][b];
}
int lca(int x,int y)
{
int dx=d[x]-d[y],i;
if(dx<)swap(x,y),dx=-dx;
for(i=;dx;++i,dx>>=)if(dx&)x=fa[i][x];
if(x==y)return x;
for(i=LG;i>=;--i)if(fa[i][x]!=fa[i][y])x=fa[i][x],y=fa[i][y];
return fa[][x];
}
int main()
{
int n,m,i,j,x,y,l=,lx=,ly=;
n=read();m=read();
for(i=;i<=n;++i)mp[c[i]=read()]?:mp[c[i]]=++cnt;
for(i=;i<=n;++i)c[i]=mp[c[i]];
for(i=;i<n;++i)ins(read(),read());
cnt=;pre();
for(i=;i<=LG;++i)for(j=;j<=n;++j)fa[i][j]=fa[i-][fa[i-][j]];
for(i=;i<=cnt;++i)for(j=;j<=cnt;++j)
for(x=p[i],y=p[j];x!=y;)
if(d[x]>d[y])cal(i,j,x),x=fa[][x];
else cal(i,j,y),y=fa[][y];
while(m--)
{
i=b[x=read()^l];j=b[y=read()];
if(x==lx&&y==ly){printf("%d\n",l);continue;}
cal(i,j,q[qr=]=lca(lx=x,ly=y));
while(x!=p[i])cal(i,j,q[++qr]=x),x=fa[][x];
while(y!=p[j])cal(i,j,q[++qr]=y),y=fa[][y];
printf("%d\n",l=ans[i][j]);
for(x=;x<=qr;++x)cal(i,j,q[x]);
}
}
正解

#include<cstdio>
#include<algorithm>
#include<map>
using namespace std;
inline int read()
{
int x,f=;char c;
while((c=getchar())<''||c>'')if(c=='-')f=;
for(x=c-'';(c=getchar())>=''&&c<='';)x=x*+c-'';
return f?x:-x;
}
#define MN 40000
#define K 200
#define LG 15
map<int,int> mp;
struct edge{int nx,t;}e[MN*+];
int h[MN+],en,c[MN+],cnt,fa[LG+][MN+],d[MN+],s[MN+],ht[MN+],q[MN+],qn;
int b[MN+],p[K+],u[MN+],ans[K+][MN+],a[MN+][K],v[MN+][K],vn;
inline void ins(int x,int y)
{
e[++en]=(edge){h[x],y};h[x]=en;
e[++en]=(edge){h[y],x};h[y]=en;
}
void pre(int x)
{
for(int i=h[x];i;i=e[i].nx)if(e[i].t!=fa[][x])
{
fa[][e[i].t]=x;d[e[i].t]=d[x]+;
pre(e[i].t);
s[x]+=s[e[i].t];ht[x]=max(ht[x],ht[e[i].t]+);
}
if(++s[q[++qn]=x],(ht[x]=max(ht[x],))==K||x<)
{for(p[++cnt]=x;s[x]--;)b[q[qn--]]=cnt;ht[x]=s[x]=;}
}
void dfs(int k,int x,int f)
{
if(!u[c[x]]++)++ans[k][x];
if(!f)ans[k][fa[][x]]=ans[k][x],dfs(k,fa[][x],x);
else for(int i=h[x];i;i=e[i].nx)if(e[i].t!=f)
ans[k][e[i].t]=ans[k][x],dfs(k,e[i].t,x);
--u[c[x]];
}
void build(int x)
{
int i,j=c[x]/K,k=c[x]%K;
for(i=;i<K;++i)a[x][i]=a[fa[][x]][i];
for(++vn,i=;i<K;++i)v[vn][i]=v[a[x][j]][i];
v[a[x][j]=vn][k]=d[x];
for(i=h[x];i;i=e[i].nx)if(e[i].t!=fa[][x])build(e[i].t);
}
int lca(int x,int y)
{
int dx=d[x]-d[y],i;
if(dx<)swap(x,y),dx=-dx;
for(i=;dx;++i,dx>>=)if(dx&)x=fa[i][x];
if(x==y)return x;
for(i=LG;i>=;--i)if(fa[i][x]!=fa[i][y])x=fa[i][x],y=fa[i][y];
return fa[][x];
}
int vio(int x,int y)
{
int res=;
for(qn=;x!=y;)
d[x]>d[y]?(u[q[++qn]=c[x]]++?:++res,x=fa[][x]):
(u[q[++qn]=c[y]]++?:++res,y=fa[][y]);
u[q[++qn]=c[x]]++?:++res;
while(qn)u[q[qn--]]=;
return res;
}
int main()
{
int n,m,i,j,x,y,l=;
n=read();m=read();
for(i=;i<=n;++i)mp[c[i]=read()]?:mp[c[i]]=++cnt;
for(i=;i<=n;++i)c[i]=mp[c[i]]-;
for(i=;i<n;++i)ins(read(),read());
cnt=;pre(d[]=);
for(i=;i<=LG;++i)for(j=;j<=n;++j)fa[i][j]=fa[i-][fa[i-][j]];
for(i=;i<=cnt;++i)dfs(i,p[i],);
build();
while(m--)
{
x=read()^l;y=read();
if(b[x]==b[y])l=vio(x,y);
else
{
if(d[p[b[x]]]<d[p[b[y]]])swap(x,y);
l=ans[b[x]][y];j=d[lca(x,y)];
for(i=x;i!=p[b[x]];i=fa[][i])if(!u[c[i]]++)
if(max(v[a[p[b[x]]][c[i]/K]][c[i]%K],v[a[y][c[i]/K]][c[i]%K])<j)++l;
for(i=x;i!=p[b[x]];i=fa[][i])u[c[i]]=;
}
printf("%d\n",l);
}
}

[BZOJ]2589: Spoj 10707 Count on a tree II的更多相关文章

  1. 【BZOJ2589】 Spoj 10707 Count on a tree II

    BZOJ2589 Spoj 10707 Count on a tree II Solution 吐槽:这道题目简直...丧心病狂 如果没有强制在线不就是树上莫队入门题? 如果加了强制在线怎么做? 考虑 ...

  2. BZOJ2539 Spoj 10707 Count on a tree II

    题面 题解 因为这道题目我也不太会做,所以借鉴了一下大佬heyujun的博客 如果不强制在线,这道题目是树上莫队练手题 我们知道莫队是离线的,但是万一强制在线就凉凉了 于是我们就需要一些操作:树分块 ...

  3. bzoj2589: Spoj 10707 Count on a tree II

    Description 给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v),你需要回答u xor lastans和v这两个节点间有多少种不同的点权.其中lastans是上一个询问的答案,初 ...

  4. 【SPOJ】Count On A Tree II(树上莫队)

    [SPOJ]Count On A Tree II(树上莫队) 题面 洛谷 Vjudge 洛谷上有翻译啦 题解 如果不在树上就是一个很裸很裸的莫队 现在在树上,就是一个很裸很裸的树上莫队啦. #incl ...

  5. BZOJ 2588: Spoj 10628. Count on a tree [树上主席树]

    2588: Spoj 10628. Count on a tree Time Limit: 12 Sec  Memory Limit: 128 MBSubmit: 5217  Solved: 1233 ...

  6. BZOJ 2588: Spoj 10628. Count on a tree 树上跑主席树

    2588: Spoj 10628. Count on a tree Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://www.lydsy.com/J ...

  7. Bzoj 2588: Spoj 10628. Count on a tree 主席树,离散化,可持久,倍增LCA

    题目:http://www.lydsy.com/JudgeOnline/problem.php?id=2588 2588: Spoj 10628. Count on a tree Time Limit ...

  8. BZOJ 2588: Spoj 10628. Count on a tree( LCA + 主席树 )

    Orz..跑得还挺快的#10 自从会树链剖分后LCA就没写过倍增了... 这道题用可持久化线段树..点x的线段树表示ROOT到x的这条路径上的权值线段树 ----------------------- ...

  9. bzoj 2588 Spoj 10628. Count on a tree (可持久化线段树)

    Spoj 10628. Count on a tree Time Limit: 12 Sec  Memory Limit: 128 MBSubmit: 7669  Solved: 1894[Submi ...

随机推荐

  1. HDFS之HA机制

  2. Beta阶段敏捷冲刺报告-DAY1

    Beta阶段敏捷冲刺报告-DAY1 Scrum Meeting 敏捷开发日期 2017.11.2 讨论时间 20:30 讨论地点 下课路上以及院楼侧门 参会人员 项目组全体成员 会议内容 附加功能讨论 ...

  3. SaaS的那些事儿

    前两年...   大一大二期间,不知道软件架构.云服务器.数据库为何物,偶尔听过却从未用过.天天学的写的东西都是一些命令行代码,所幸在学完<数据结构>和<算法导论>后能够独立实 ...

  4. ExtJs6级联combo的实现

    父类获取子类进行操作 { xtype: 'combo', store: Common.Dic.getDicData("IMAGE_BIG_TYPE") , multiSelect: ...

  5. CSS揭秘(三)形状

    Chapter 3 1. 椭圆 椭圆的实现主要依靠 border-radius 属性,该属性确定边框切圆角的半径大小,可以指定数值 px,也可以使用百分比显示 而且该属性非常灵活,四个角可以分别设置 ...

  6. Python之旅.第四章.模块与包 4.02

    一.模块的使用之import 1 什么是模块?模块就一系统功能的集合体,在python中,一个py文件就是一个模块,比如module.py,其中模块名module2 使用模块2.1 import 导入 ...

  7. windows安装gcc编译器

    由于vc6.0对c语言编译不是很好,有些语句是正确的,但是编译却不能通过 所以决定在windows中安装gcc编译器来使用! http://www.cnblogs.com/cryinstall/arc ...

  8. 不允许用(a+b)/2这种方式求两个数的均值;如下程序在Linux和32位集成开发环境中运行

    #define MAX(a,b) ((a)>(b)?(a):(b)) #include<stdio.h> int main() { int a = 10; int b = 20; i ...

  9. js中严格模式

    我们在js中可以使用"use strict";定义了我们在接下来的文档输写中 将按照严格模式进行: function(){ "use strict'; ;// 在这里我们 ...

  10. HTTP协议扫盲(五)HTTP请求防篡改

    相关链接: http://www.cnblogs.com/ziyi--caolu/p/4742577.html 请求防重放:http://www.2cto.com/kf/201612/573045.h ...