用dfs序把询问表示成询问dfs序的两个区间中的信息

拆成至多9个询问(询问dfs序的两个前缀),对这些询问用莫队处理,时间复杂度$O(n\sqrt{m})$

#include<bits/stdc++.h>
typedef long long i64;
const int N=1e5+;
char buf[N],*ptr=buf+,ob[N],*op=ob;
int G(){
if(ptr-buf==)fread(ptr=buf,,,stdin);
return *ptr++;
}
int _(){
int x=;
if(ptr-buf<){
while(*ptr<)++ptr;
while(*ptr>)x=x*+*ptr++-;
}else{
int c=G();
while(c<)c=G();
while(c>)x=x*+c-,c=G();
}
return x;
}
#define fl fwrite(ob,1,op-ob,stdout),op=ob
void pr(i64 x){
if(op-ob>)fl;
int ss[],sp=;
if(!x)*op++=;
while(x)ss[++sp]=x%,x/=;
while(sp)*op++=ss[sp--]+;
*op++=;
}
i64 ans[N*];
int n,m,rt=;
int v[N],vs[N],qc=;
int es[N*],enx[N*],e0[N],ep=;
int fa[N],sz[N],son[N],dep[N],top[N],id[N][],vi[N],idp=;
void f1(int w,int pa){
dep[w]=dep[fa[w]=pa]+;
sz[w]=;
for(int i=e0[w];i;i=enx[i]){
int u=es[i];
if(u==pa)continue;
f1(u,w);
sz[w]+=sz[u];
if(sz[u]>sz[son[w]])son[w]=u;
}
}
void f2(int w,int tp){
id[w][]=++idp;
vi[idp]=v[w];
top[w]=tp;
if(son[w])f2(son[w],tp);
for(int i=e0[w];i;i=enx[i]){
int u=es[i];
if(u!=fa[w]&&u!=son[w])f2(u,u);
}
id[w][]=idp;
}
int up(int x,int y){
int a=top[x],b=top[y];
while(a!=b){
x=fa[a];
if(x==y)return a;
a=top[x];
}
return son[y];
}
bool chk(int w){
return id[w][]<id[rt][]&&id[rt][]<=id[w][];
}
int pos[N],B,qp=;
struct Q{
int l,r,sgn,id;
}qs[N*],qs1[N*],*ls[N],*lp;
int tr[N],tb[N];
i64 s0[N],_ans;
int ts[N][];
inline void inc0(int x){++ts[x][],_ans+=ts[x][];}
inline void dec0(int x){--ts[x][],_ans-=ts[x][];}
inline void inc1(int x){++ts[x][],_ans+=ts[x][];}
inline void dec1(int x){--ts[x][],_ans-=ts[x][];}
void cal(int w,int*a,int&p){
if(w==rt)a[]=n,p=;
else if(id[w][]<id[rt][]&&id[rt][]<=id[w][]){
w=up(rt,w);
a[]=n;
a[]=-id[w][];
a[]=id[w][]-;
p=;
}else{
a[]=id[w][];
a[]=-id[w][];
p=;
}
}
void ins(int a,int b,int id){
if(!(a&&b))return;
int c=;
if(a<)a=-a,c=-c;
if(b<)b=-b,c=-c;
if(a>b)std::swap(a,b);
if(b==n)ans[id]+=c*s0[a];
else qs[qp++]=(Q){a,b,c,id};
}
int main(){
n=_();m=_();
for(int i=;i<=n;++i)v[i]=vs[i]=_();
std::sort(vs+,vs+n+);
for(int i=;i<=n;++i)v[i]=std::lower_bound(vs+,vs+n+,v[i])-vs;
for(int i=,a,b;i<n;++i){
a=_(),b=_();
es[ep]=b;enx[ep]=e0[a];e0[a]=ep++;
es[ep]=a;enx[ep]=e0[b];e0[b]=ep++;
}
f1(,);
f2(,);
for(int i=;i<=n;++i)inc0(vi[i]);
for(int i=;i<=n;++i)inc1(vi[i]),s0[i]=_ans;
_ans=;
memset(ts,,sizeof(ts));
for(int i=;i<=m;++i){
if(_()==)rt=_();
else{
++qc;
int x=_(),y=_();
int xv[],xp,yv[],yp;
cal(x,xv,xp);
cal(y,yv,yp);
for(int a=;a<xp;++a)
for(int b=;b<yp;++b)ins(xv[a],yv[b],qc);
}
}
B=n/sqrt(qp+)*+;
for(int i=;i<=n;++i)pos[i]=i/B; for(int i=;i<qp;++i)++tr[qs[i].r],++tb[pos[qs[i].l]];
lp=qs1;
for(int i=;i<=n;++i)ls[i]=lp,lp+=tr[i];
for(int i=;i<qp;++i)*ls[qs[i].r]++=qs[i];
lp=qs;
for(int i=;i<=pos[n];++i)ls[i]=lp,lp+=tb[i];
for(int i=;i<qp;++i)*ls[pos[qs1[i].l]]++=qs1[i];
for(int i=;i<pos[n];i+=)std::reverse(ls[i],ls[i+]); int L=,R=;
for(int i=;i<qp;++i){
int l=qs[i].l,r=qs[i].r;
while(L<l)inc0(vi[++L]);
while(L>l)dec0(vi[L--]);
while(R<r)inc1(vi[++R]);
while(R>r)dec1(vi[R--]);
ans[qs[i].id]+=qs[i].sgn*_ans;
}
for(int i=;i<=qc;++i)pr(ans[i]);
return fl,;
}

bzoj4940: [Ynoi2016]这是我自己的发明的更多相关文章

  1. bzoj4940 [Ynoi2016]这是我自己的发明 莫队+dfs序

    题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=4940 题解 对于换根操作,处理方法就很套路了. 首先先假定以 \(1\) 为根做一遍 dfs, ...

  2. 【bzoj4940】[Ynoi2016]这是我自己的发明 DFS序+树上倍增+莫队算法

    题目描述 给一个树,n 个点,有点权,初始根是 1. m 个操作,每次操作: 1. 将树根换为 x. 2. 给出两个点 x,y,从 x 的子树中选每一个点,y 的子树中选每一个点,如果两个点点权相等, ...

  3. 【bzoj4940】这是我自己的发明

    Portal --> bzoj4940 Solution (原题这题面到底是..怎么回事啊深深的套路qwq) 感觉自己对根号的算法还是很..没有感觉啊== 实际上这题和bzoj5016没有任何区 ...

  4. 洛谷P4689 [Ynoi2016]这是我自己的发明(莫队,树的dfn序,map,容斥原理)

    洛谷题目传送门 具体思路看别的题解吧.这里只提两个可能对常数和代码长度有优化的处理方法. I 把一个询问拆成\(9\)个甚至\(16\)个莫队询问实在是有点珂怕. 发现询问的一边要么是一个区间,要么是 ...

  5. [Ynoi2016]这是我自己的发明 莫队

    传送门:here 很棒的莫队题啊..... 题意: 有一棵$ n$个点的树,树上每个点有点权,有$ m$次询问: 操作1:给定两个点$ x,y$,求二元组$ (a,b)$的数量,要求$ a$在$ x$ ...

  6. 洛谷P4689 [Ynoi2016]这是我自己的发明 [莫队]

    传送门 ynoi中比较良心不卡常的题. 思路 没有换根操作时显然可以变成dfs序莫队随便搞. 换根操作时一个子树可以变成两段区间的并集,也随便搞搞就好了. 这题完全不卡常,随便过. 代码 #inclu ...

  7. [Ynoi2016]这是我自己的发明(莫队)

    话说这道题数据是不是都是链啊,我不手动扩栈就全 \(RE\)... 不过 \(A\) 了这题还是很爽的,通过昨晚到今天早上的奋斗,终于肝出了这题 其实楼上说的也差不多了,就是把区间拆掉然后莫队瞎搞 弱 ...

  8. YNOI2016 这是我自己的发明

    看到这个标题立刻想到:. “绝地科学家,八倍不屏息啊,八百里外把头打啊...” 首先我们发现如果只考虑第二个操作,这棵树就是假的,我们可以直接莫队解决 如果考虑换根的话...可以把一个操作换成小于等于 ...

  9. Luogu4689 [Ynoi2016]这是我自己的发明 【莫队】

    题目链接:洛谷 又来做Ynoi里面的水题了... 首先换根的话是一个套路,首先以1为根dfs,然后画一画就知道以rt为根,x的子树是什么了.可以拆分为2个dfs连续段. 然后如果要计算\([l_1,r ...

随机推荐

  1. js学习:return arguments

    return函数 arguments

  2. 20155219实验三 敏捷开发与XP实践

    实验内容 XP基础 XP核心实践 相关工具 敏捷开发与XP 1.敏捷开发(Agile Development)是一种以人为核心.迭代.循序渐进的开发方法."敏捷流程"是一系列价值观 ...

  3. XXS level3

    (1)用level1和2的方法都行不通,查看PHP源代码,发现url与输入框内容都进行了过滤 <?php ini_set("display_errors", 0); $str ...

  4. Python基础进程和线程

    一 背景知识 进程的概念起源于操作系统,是操作系统最核心的概念. 进程是对正在运行程序的一个抽象,操作系统的其他所有内容都是围绕进程的概念展开的.所以想要真正了解进程,必须事先了解操作系统,egon介 ...

  5. 字符常量 java

    从Java语言的定义,ABCD都是错误的,4个都不是正确的字符常量.可以查阅<JLS8>中的描述: A character literal is expressed as a charac ...

  6. 【git】一台机器上使用不同的git账号

    1.生成一个新的自定义名称的公钥: ssh-keygen -t rsa -C "shangxiaofei3@163.com" -f ~/.ssh/sxfself 一直点击回车 执行 ...

  7. 【jar包删除,再添加版本更高的jar】******.jar in project cnnot be read or is not a valid

    把4.2.0删除,然后添加其他版本的jar包

  8. href和src区别

    href常见于link a 元素, 是Hypertext Reference的缩写,表示超文本引用.用来建立当前元素和文档之间的链接. href引用css文件时,浏览器会识别该文档为css文档,就会并 ...

  9. 性能测试之mysql监控、优化

    我们在做性能测试的目的是什么,就是要测出一个系统的瓶颈在哪里,到底是哪里影响了我们系统的性能,找到问题,然后解决它.当然一个系统由很多东西一起组合到一起,应用程序.数据库.服务器.中中间件等等很多东西 ...

  10. MySQL ERROR 2005 (HY000)

    问题 使用 docker run -it --rm mysql mysql -h 192.168.18.133:3306 -uroot -p 连接远程mysql服务器时,ERROR 2005 (HY0 ...