题目大意

  给你一棵\(n\)个点的树,每个点有一个颜色\(c_i\),每次给你\(x,y,k\),求从\(x\)到\(y\)的路径上出现次数第\(k\)多的颜色的出现次数

  \(n,q\leq 100000\)

题解

  树上莫队

  先求出这棵树的dfs序(括号序列),记录每个点第一次出现的位置\(st_x\)和最后一次出现的位置\(ed_x\)

  

  若每次询问的\(x,y\)中有一个是另一个的祖先(设\(x\)是\(y\)的祖先),那么就可以视为询问区间\([st_x,st_y]\)

  可是一些不在这条链上的点会出现两次,我们把出现两次的点视为没出现过。

  

  否则就视为询问\([ed_x,st_y]\)(设\(st_x<st_y\))。但是\(lca\)处没有被统计到。直接暴力把\(lca\)处的贡献统计一下就可以了。

  

  其他的和普通莫队一样了。

  时间复杂度:\(O((n+q)\sqrt{n})\)

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<ctime>
#include<utility>
#include<list>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
list<int> l[200010];
int f[200010][20];
int st[500010];
int ed[500010];
int ti;
int w[1000010];
int c[500010];
int a[500010];
int e[500010];
int d[500010];
int m;
void dfs(int x,int fa,int dep)
{
st[x]=++ti;
w[ti]=x;
d[x]=dep;
f[x][0]=fa;
int i;
for(i=1;i<=19;i++)
f[x][i]=f[f[x][i-1]][i-1];
for(auto v:l[x])
if(v!=fa)
dfs(v,x,dep+1);
ed[x]=++ti;
w[ti]=x;
}
int getlca(int x,int y)
{
if(d[x]<d[y])
swap(x,y);
int i;
for(i=19;i>=0;i--)
if(d[f[x][i]]>=d[y])
x=f[x][i];
if(x==y)
return x;
for(i=19;i>=0;i--)
if(f[x][i]!=f[y][i])
{
x=f[x][i];
y=f[y][i];
}
return f[x][0];
}
int bl;
int ans[500010];
int a1[500010];
int a2[500010];
int g[500010];
int n,q;
struct p
{
int l,r;
int k;
int id;
int b;
int c;
p()
{
c=b=l=r=k=id=0;
}
};
p b[500010];
int cmp(p a,p b)
{
if(a.b!=b.b)
return a.b<b.b;
return a.r<b.r;
}
int block[500010];
int *c1[500010];
int *t[500010];
void add(int x)
{
a1[x]++;
// x=(x+bl-1)/bl;
// a2[x]++;
(*c1[x])++;
}
void del(int x)
{
a1[x]--;
// x=(x+bl-1)/bl;
// a2[x]--;
(*c1[x])--;
}
void change(int x)
{
// int &b=g[c[x]];
int &b=*t[x];
if(a[x])
{
a[x]=0;
// del(b);
a1[b]--;
(*c1[b])--;
b--;
// add(b);
a1[b]++;
(*c1[b])++;
}
else
{
a[x]=1;
// del(b);
a1[b]--;
(*c1[b])--;
b++;
// add(b);
a1[b]++;
(*c1[b])++;
}
}
int num;
int query(int k)
{
int i,j;
for(i=num;i>=1;i--)
if(a2[i]>=k)
{
j=min(n,i*bl);
for(;;j--)
if(a1[j]>=k)
return j;
else
k-=a1[j];
}
else
k-=a2[i];
return 0;
}
void rd(int &s)
{
int c;
while((c=getchar())<'0'||c>'9');
s=c-'0';
while((c=getchar())>='0'&&c<='9')
s=s*10+c-'0';
}
int main()
{
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
// scanf("%d%d",&n,&q);
rd(n);
rd(q);
bl=500;
int m=0;
int i;
for(i=1;i<=n;i++)
{
// scanf("%d",&c[i]);
rd(c[i]);
e[++m]=c[i];
}
sort(e+1,e+m+1);
m=unique(e+1,e+m+1)-e-1;
for(i=1;i<=n;i++)
c[i]=lower_bound(e+1,e+m+1,c[i])-e;
int x,y;
for(i=1;i<n;i++)
{
// scanf("%d%d",&x,&y);
rd(x);
rd(y);
l[x].push_back(y);
l[y].push_back(x);
}
dfs(1,0,1);
num=(n+bl-1)/bl;
for(i=0;i<=n;i++)
{
c1[i]=&a2[(i+bl-1)/bl];
t[i]=&g[c[i]];
}
for(i=1;i<=q;i++)
{
// scanf("%d%d%d",&x,&y,&b[i].k);
rd(x);
rd(y);
rd(b[i].k);
b[i].id=i;
if(st[x]<=st[y]&&ed[x]>=ed[y])
{
b[i].l=st[x];
b[i].r=st[y];
b[i].c=0;
}
else if(st[y]<=st[x]&&ed[y]>=ed[x])
{
b[i].l=st[y];
b[i].r=st[x];
b[i].c=0;
}
else
{
if(st[x]>st[y])
swap(x,y);
b[i].l=ed[x];
b[i].r=st[y];
b[i].c=1;
}
b[i].b=(b[i].l+bl-1)/bl;
}
sort(b+1,b+q+1,cmp);
int l=1,r=0;
for(i=1;i<=q;i++)
{
while(r<b[i].r)
change(w[++r]);
while(l>b[i].l)
change(w[--l]);
while(r>b[i].r)
change(w[r--]);
while(l<b[i].l)
change(w[l++]);
if(b[i].c)
{
int lca=getlca(w[b[i].l],w[b[i].r]);
change(lca);
ans[b[i].id]=query(b[i].k);
change(lca);
}
else
ans[b[i].id]=query(b[i].k);
}
for(i=1;i<=q;i++)
printf("%d\n",ans[i]);
return 0;
}

【XSY1642】Another Boring Problem 树上莫队的更多相关文章

  1. 【bzoj4129】Haruna’s Breakfast 带修改树上莫队+分块

    题目描述 给出一棵树,点有点权.支持两种操作:修改一个点的点权,查询链上mex. 输入 第一行包括两个整数n,m,代表树上的结点数(标号为1~n)和操作数.第二行包括n个整数a1...an,代表每个结 ...

  2. 【BZOJ 3735】苹果树 树上莫队(树分块+离线莫队+鬼畜的压行)

    2016-05-09 UPD:学习了新的DFS序列分块,然后发现这个东西是战术核导弹?反正比下面的树分块不知道要快到哪里去了 #include<cmath> #include<cst ...

  3. 【BZOJ-3757】苹果树 块状树 + 树上莫队

    3757: 苹果树 Time Limit: 20 Sec  Memory Limit: 256 MBSubmit: 1305  Solved: 503[Submit][Status][Discuss] ...

  4. [BZOJ 3052] [wc2013] 糖果公园 【树上莫队】

    题目链接:BZOJ - 3052 题目分析 这道题就是非常经典的树上莫队了,并且是带修改的莫队. 带修改的莫队:将询问按照 左端点所在的块编号为第一关键字,右端点所在的块为第二关键字,位于第几次修改之 ...

  5. 树上莫队 wowow

    构建:像线性的莫队那样,依旧是按sqrt(n)为一块分块. int dfs(int x){ ; dfn[x]=++ind; ;i<=;i++) if (bin[i]<=deep[x]) f ...

  6. spoj COT2 - Count on a tree II 树上莫队

    题目链接 http://codeforces.com/blog/entry/43230树上莫队从这里学的,  受益匪浅.. #include <iostream> #include < ...

  7. BZOJ 4129: Haruna’s Breakfast [树上莫队 分块]

    传送门 题意: 单点修改,求一条链的mex 分块维护权值,$O(1)$修改$O(S)$求mex...... 带修改树上莫队 #include <iostream> #include < ...

  8. 【WC2013】糖果公园 [树上莫队]

    题意: 一棵树,修改一个点的颜色,询问两点路径上每种颜色的权值$val[c]$*出现次数的权值$cou[w[c]]$的和 sro VFK 树上莫队 按照王室联邦的方法分块,块的大小直径个数有保证,并不 ...

  9. Codeforces 852I Dating 树上莫队

    Dating 随便树上莫队搞一搞就好啦. #include<bits/stdc++.h> #define LL long long #define LD long double #defi ...

随机推荐

  1. iStack堆叠介绍

    iStack堆叠技术简介:   网络中主要存在两种形态的通信设备:盒式设备和框式设备.通常盒式设备部署在网络接入层或对可靠性要求不高的汇聚层,盒式单机设备对端口和带宽扩容不够灵活,扩容增加新的盒式设备 ...

  2. poj3468 线段树的懒惰标记

    题目链接:poj3468 题意:给定一段数组,有两种操作,一种是给某段区间加c,另一种是查询一段区间的和 思路:暴力的方法是每次都给这段区间的点加c,查询也遍历一遍区间,复杂度是n*n,肯定过不去,另 ...

  3. Python学习第十三篇——函数的深层次运用

    def make_pizza(size,*toppings): print("\nmaking a "+str(size)+" size pizza with follo ...

  4. Array Queries CodeForces - 797E

    题目链接 非常好的一道题目, 分析,如果用暴力的话,时间复杂度是O(q*n)稳稳的超时 如果用二维DP的话,需要O (n*n)的空间复杂度,会爆空间. 那么分析一下,如果k>sqrt(n)的话, ...

  5. semantic-ui 分割线

    分割线即原生html中的<hr>标签.不过semantic-ui中将<hr>美化了一下下. 1.基础分割线 需要注意的是分割线只能使用div标签和p标签,不能使用span标签. ...

  6. PAT L2-007 家庭房产

    https://pintia.cn/problem-sets/994805046380707840/problems/994805068539215872 给定每个人的家庭成员和其自己名下的房产,请你 ...

  7. SpringMVC+Spring+Mybatis+AngularJS 多规格保存示例代码

    insert时拿到最新增加的id值 绑定参数 js 实体类 Service实现类 Controller

  8. C# Note21: 扩展方法(Extension Method)及其应用

    前言 今天在开会时提到的一个概念,入职3个多月多注重在项目中使用C#的编程知识,一直没有很认真地过一遍C#的全部语法,当我们新人被问及是否了解Extension Method时,一时之间竟不能很通俗准 ...

  9. Hbase数据表解析

    demo为表的命名空间,user为表的名字you2个列族,一个为b.一个为o. NAME 为列族名,Replication_SCOPE实现一个远程集群的复制.compression数据压缩的类型 Hb ...

  10. 莫烦scikit-learn学习自修第一天【scikit-learn安装】

    1. 机器学习的分类 (1)有监督学习(包括分类和回归) (2)无监督学习(包括聚类) (3)强化学习 2. 安装 (1)安装python (2)安装numpy >=1.6.1 (3)安装sci ...