[Ynoi2016]这是我自己的发明 莫队
传送门:here
很棒的莫队题啊.....
题意:
有一棵$ n$个点的树,树上每个点有点权,有$ m$次询问:
操作1:给定两个点$ x,y$,求二元组$ (a,b)$的数量,要求$ a$在$ x$的子树内,$ b$在$ y$的子树内,且$ a$和$ b$的权值相同
操作2:给定点$ x$,将根节点换成$ x$
$ solution:$
我们先考虑没有换根操作
我们先求出这棵树所有点的dfs序,然后可以把树上问题转化成区间询问
$ \sum\limits_{i=L1}^{R1}\sum\limits_{j=L2}^{R2}[ value[i]=value[j] ]$
会发现这就是LOJ2254
我们令$ g(x,L,R)$表示区间$ [L,R]$中x的数量
则原式等价于$ \sum\limits_{x}g(x,L1,R1)g(x,L2,R2)$
化成前缀相减的形式:$ \sum\limits_{x}(g(x,1,R1)-g(x,1,L1-1))(g(x,1,R2)-g(x,L2-1,R2))$
令$ f(a,b)=\sum\limits_{i=1}^{a}\sum\limits_{j=1}^{b}[ value[i]=value[j] ]$
会发现可以化简成$ f(R1,R2)-f(L1-1,R2)-f(R1,L2-1)+f(L1-1,L2-1)$
对于每个$ f(a,b)$,我们记录它的符号以及在第几个询问里,然后可以直接挂在莫队上跑
然后考虑如果有换根操作
我们假定原先的根为$ 1$
然后假设将根换成了$ x$并且询问$ k$的统治区间
我们分三类讨论
$ 1.k=x$
此时子树范围为整个区间
$ 2.k$在$1...x$的路径上
显然$ k$是$ x$的祖先
找出$ k$的孩子中也是$ x$的祖先的节点
设这个节点在以一号点为根时的子树范围为$ [L,R]$
则此时$ k$的统治范围为$ [1,L-1]并上[R+1,n]$
$ 3. othercase $
此时子树和以1为根的子树没有区别
这样我们将每次询问拆成若干区间
然后用上面没有换根的时候的方法扔进莫队暴力计算
可以通过此题
附上我的代码(人菜自带大常数)
#include<ctime>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define M 200010
#define ll long long
using namespace std;
int i,j,k,m,n,x,y,z,cnt,w;ll now;
int up[][M],F[M],L[M],N[M],a[M],fa[M],size[M],deep[M],v[M],dfn[M],to[M];
int sum[M][];
inline ll read(){
ll x = ; char zf = ; char ch = getchar();
while (ch != '-' && !isdigit(ch)) ch = getchar();
if (ch == '-') zf = -, ch = getchar();
while (isdigit(ch)) x = x * + ch - '', ch = getchar(); return x * zf;
}
void write(ll y){if(y<)putchar('-'),y=-y;if(y>)write(y/);putchar(y%+);}
void writeln(const ll y){write(y);putchar('\n');}
inline void ins(const int x,const int p){
now+=sum[x][p^];
sum[x][p]++;
}
inline void del(const int x,const int p){
now-=sum[x][p^];
sum[x][p]--;
}
struct query{
int L,R,id,zf,p;
inline bool operator <(const query s)const{
return (p==s.p)?(R<s.R):(p<s.p);
}
}q[];
void add(int x,int y){
a[++k]=y;
if(!F[x])F[x]=k;
else N[L[x]]=k;
L[x]=k;
}
void dfs(int x,int pre){
dfn[x]=++cnt;to[cnt]=x;
up[][x]=pre;size[x]=;
for(int i=F[x];i;i=N[i])if(a[i]!=pre){
deep[a[i]]=deep[x]+;
dfs(a[i],x);
size[x]+=size[a[i]];
}
}
int son(int x,int y){//求出x的孩子中是y的祖先的那个孩子
for(int i=,s=deep[y]-deep[x]-;s;i++)if(s>>i&)s^=(<<i),y=up[i][y];
return y;
}
bool in(int x,int y){//判断x是否为y的祖先
return dfn[x]<=dfn[y]&&dfn[x]+size[x]->=dfn[y];
}
void add(int id,int L1,int R1,int L2,int R2){//将其加入莫队询问
q[++cnt]={R1,R2,id,,R1/w};
if(L1>)q[++cnt]={L1-,R2,id,-,(L1-)/w};
if(L2>)q[++cnt]={R1,L2-,id,-,R1/w};
if(L1>&&L2>)q[++cnt]={L1-,L2-,id,,(L1-)/w};
}
struct now{
int L,R;
}aa[],bb[];
ll ans[];
struct w{
int x,id;
inline bool operator <(const w s)const{
return x<s.x;
}
}c[];
int main(){
n=read();m=read();w=;
for(int i=;i<=n;i++)c[i].x=read(),c[i].id=i;
sort(c+,c+n+);int vv=;
for(int i=;i<=n;i++){
if(i==||c[i].x!=c[i-].x)vv++;
v[c[i].id]=vv;
}//离散化
for(int i=;i<n;i++){
x=read();y=read();
add(x,y);
add(y,x);
}
dfs(,);cnt=;
for(int i=;i<=;i++)
for(int j=;j<=n;j++)
up[i][j]=up[i-][up[i-][j]];
int nowroot=,tot=;
for(int i=;i<=m;i++){
int opt=read();
if(opt==){
nowroot=read();
continue;
}
x=read();y=read();tot++;
int cnt1=,cnt2=;
if(x==nowroot)aa[++cnt1]={,n};
else if(in(x,nowroot)){
int pl=son(x,nowroot);
aa[++cnt1]={,dfn[pl]-};
aa[++cnt1]={dfn[pl]+size[pl],n};
}
else aa[++cnt1]={dfn[x],dfn[x]+size[x]-}; if(y==nowroot)bb[++cnt2]={,n};
else if(in(y,nowroot)){
int pl=son(y,nowroot);
bb[++cnt2]={,dfn[pl]-};
bb[++cnt2]={dfn[pl]+size[pl],n};
}
else bb[++cnt2]={dfn[y],dfn[y]+size[y]-};
//aa和bb存询问点x,y对应的区间
ll ans=;
for(int q1=;q1<=cnt1;q1++)
for(int q2=;q2<=cnt2;q2++)
add(tot,aa[q1].L,aa[q1].R,bb[q2].L,bb[q2].R);//加入询问
}
sort(q+,q+cnt+);
int L=,R=;now=;
for(int i=;i<=cnt;i++){
while(L<q[i].L)ins(v[to[++L]],);
while(L>q[i].L)del(v[to[L--]],);
while(R<q[i].R)ins(v[to[++R]],);
while(R>q[i].R)del(v[to[R--]],);
ans[q[i].id]+=now*q[i].zf;//莫队计算
}
for(int i=;i<=tot;i++)writeln(ans[i]);
return ;
}
[Ynoi2016]这是我自己的发明 莫队的更多相关文章
- 洛谷P4689 [Ynoi2016]这是我自己的发明 [莫队]
传送门 ynoi中比较良心不卡常的题. 思路 没有换根操作时显然可以变成dfs序莫队随便搞. 换根操作时一个子树可以变成两段区间的并集,也随便搞搞就好了. 这题完全不卡常,随便过. 代码 #inclu ...
- bzoj4940 [Ynoi2016]这是我自己的发明 莫队+dfs序
题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=4940 题解 对于换根操作,处理方法就很套路了. 首先先假定以 \(1\) 为根做一遍 dfs, ...
- 【洛谷 P4688】 [Ynoi2016]掉进兔子洞(bitset,莫队)
题目链接 第一道Ynoi 显然每次询问的答案为三个区间的长度和减去公共数字个数*3. 如果是公共数字种数的话就能用莫队+bitset存每个区间的状态,然后3个区间按位与就行了. 但现在是个数,bits ...
- 洛谷P4689 [Ynoi2016]这是我自己的发明(莫队,树的dfn序,map,容斥原理)
洛谷题目传送门 具体思路看别的题解吧.这里只提两个可能对常数和代码长度有优化的处理方法. I 把一个询问拆成\(9\)个甚至\(16\)个莫队询问实在是有点珂怕. 发现询问的一边要么是一个区间,要么是 ...
- [Ynoi2016]这是我自己的发明(莫队)
话说这道题数据是不是都是链啊,我不手动扩栈就全 \(RE\)... 不过 \(A\) 了这题还是很爽的,通过昨晚到今天早上的奋斗,终于肝出了这题 其实楼上说的也差不多了,就是把区间拆掉然后莫队瞎搞 弱 ...
- 【bzoj4940】[Ynoi2016]这是我自己的发明 DFS序+树上倍增+莫队算法
题目描述 给一个树,n 个点,有点权,初始根是 1. m 个操作,每次操作: 1. 将树根换为 x. 2. 给出两个点 x,y,从 x 的子树中选每一个点,y 的子树中选每一个点,如果两个点点权相等, ...
- Luogu4689 [Ynoi2016]这是我自己的发明 【莫队】
题目链接:洛谷 又来做Ynoi里面的水题了... 首先换根的话是一个套路,首先以1为根dfs,然后画一画就知道以rt为根,x的子树是什么了.可以拆分为2个dfs连续段. 然后如果要计算\([l_1,r ...
- 洛谷P4689 [Ynoi2016]这是我自己的发明(树上莫队+树链剖分)
题目描述 您正在打galgame,然后突然家长进来了,于是您假装在写数据结构题: 给一个树,n 个点,有点权,初始根是 1. m 个操作,每次操作: 1.将树根换为 x. 2.给出两个点 x,y,从 ...
- luogu P4688 [Ynoi2016]掉进兔子洞 bitset 莫队
题目链接 luogu P4688 [Ynoi2016]掉进兔子洞 题解 莫队维护bitset区间交个数 代码 // luogu-judger-enable-o2 #include<cmath&g ...
随机推荐
- ImageMagick 笔记: 索引颜色(index color)、锁定图层,透明 png 转 gif (保持清晰度)
今天在处理一张 png 透明背景的图片,大小: 16KB, 尺寸: 400 x 300,用到一段代码,也许对以后有用. /** 带透明背景和阴影的png图片, 转换成 gif, [索引色] + [锁住 ...
- 关于json_encode转数组为json对象时里有数组格式数据的问题
前言:这次是给一款小程序提供接口时发现的 别的不多说,下面直接看出现问题的json数据 可以看到,这是一个大的json对象,是由多维数组组成,一般api接口提供的也是这种格式. 但是仔细看红框中的内容 ...
- Ubuntu的 g++ gcc版本升降级
更改gcc默认版本(gcc版本降级/升级) ### 以降级到gcc-6为例 >* sudo apt install gcc-6 g++-6 >* sudo update-alternati ...
- hystrix实战
https://blog.csdn.net/Ezreal_King/article/details/72942823
- P3358 最长k可重区间集问题
题目链接 \(Click\) \(Here\) 这题的写法非常巧妙. 每个位置的点向它的下一个位置连一个容量为\(INF\)的边,从区间的左端点往右端点拉一条容量为\(1\),费用为区间长度的边,从起 ...
- 【优秀的设计绘图软件】Affinity Designer Beta for Mac 1.7
[简介] Affinity Designer 1.7 beta 中文版本,具有全新的UI界面和功能,支持最新的 macOS Mojave 10.14 系统,Affinity Designer是 ...
- Prometheus-自定义Node_Exporter
标量(Scalar):一个浮点型的数字值 标量只有一个数字,没有时序. 需要注意的是,当使用表达式count(http_requests_total),返回的数据类型,依然是瞬时向量.用户可以通过内置 ...
- JavaSE_坚持读源码_ArrayList对象_Java1.7
底层的数组对象 /** * The array buffer into which the elements of the ArrayList are stored. * The capacity o ...
- 运维监控-使用Zabbix Server 创建 Actions
运维监控-使用Zabbix Server 创建 Actions 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. zabbix的action默认是关闭的,因此我们想使用它就得先启用哟. ...
- Linux下查看某个进程打开的文件数-losf工具常用参数介绍
Linux下查看某个进程打开的文件数-losf工具常用参数介绍 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 在linux操作系统中,一切皆文件.通过文件不仅仅可以访问常规数据,还 ...