用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. xdoj-1057(Lucas定理的证明及其模板)

    Lucas定理的证明: 转自百度百科(感觉写的还不错) 首先你需要这个算式:    ,其中f > 0&& f < p,然后 (1 + x) nΞ(1 + x) sp+q Ξ ...

  2. HDU 1159:Common Subsequence(LCS模板)

    Common Subsequence Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Other ...

  3. html css input定位 文本框阴影 灰色不可编辑

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  4. 【MAC】常用方法-持续更新

    1.Homebrew安装 删除brew ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/ma ...

  5. 【BZOJ2820】ygy的gcd

    不知道为什么不想写总结,只是(因为是用别人的权限号交的所以)屯一个代码 #include<iostream> #include<cstdio> #include<algo ...

  6. 【NOI2005】 聪聪可可

    树分治劲啊 原题: 聪聪和可可是兄弟俩,他们俩经常为了一些琐事打起来,例如家中只剩下最后一根冰棍而两人都想吃.两个人都想玩儿电脑(可是他们家只有一台电脑)……遇到这种问题,一般情况下石头剪刀布就好了, ...

  7. golang for 循环变量取内存地址

    前几天提交的代码进行测试的时候发现变量无法赋值,原始代码如下: for _, asset := range dspInfo.native.Assets { var resAsset protocol. ...

  8. C# to IL 18 Glossary(术语)

  9. yum 安装 Mysql 5.7,忘记密码解决方案

    Linux卸载yum安装的mysql 一.系统情况 Linux:Centos7.4(64位) Mysql:5.6 二.卸载mysql 1.查看安装了哪些mysql程序 Bash rpm -qa | g ...

  10. eclipse 视图打不开解决方法

    遇到一个eclipse问题,查看方法调用者,或打开调用层次窗口失败,这时要查看一个方法的调用者只好通过全局搜索的方式.网上搜索报错关键词没找到答案,看了一下全局设置也没有想过的选项. 后想到一个ecl ...