P4689 [Ynoi2016] 这是我自己的发明
对根为
- 换根
- 给定
,求 。
把子树计数转到 dfs 序上,发现这个就是带换根的 P5268 [SNOI2017] 一个简单的询问。
先看不换根怎么办。记
差分,记
处理换根:
-
若
,则 对应区间 。 -
若
在子树 外,则 对应区间 。 -
否则,令
为链 上离 最近的点, 对应区间 。
发现如果
均对应一段区间
上面写过了。
对应一段区间, 对应两端区间
也就是
记
发现只用拆
均对应两端区间
也能推出来是
也只用拆
取
#include<bits/stdc++.h> #define ll long long #define N 100010 #define M 500010 using namespace std; int read(){ int x=0,w=1;char ch=getchar(); while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();} while(isdigit(ch))x=(x<<3)+(x<<1)+(ch^48),ch=getchar(); return x*w; } int n,m,B,a[N]; int b[N],len; struct Q{ int l,r,id,fl; bool operator<(const Q &x)const{ if(l/B!=x.l/B)return l<x.l; return (l/B)&1?r>x.r:r<x.r; } }q[M<<2];int tq; void ins(int l,int r,int fl){ if(l>r)swap(l,r); if(l<1||r>n)return; q[++tq]={l,r,m,fl}; } vector<int>e[N]; int st[N],ed[N],tim,c[N]; int fa[N][17],dep[N]; int fath(int x,int k){ for(int i=16;~i;i--) if((k>>i)&1)x=fa[x][i]; return x; } void dfs(int u,int f){ st[u]=++tim,c[tim]=a[u]; fa[u][0]=f,dep[u]=dep[f]+1; for(int i=1;i<17;i++)fa[u][i]=fa[fa[u][i-1]][i-1]; for(int v:e[u]) if(v!=f)dfs(v,u); ed[u]=tim; } void get(int u,int rt,int &l,int &r,int &f){ if(u==rt)return l=1,r=n,f=false,void(); if(st[rt]<st[u]||ed[rt]>ed[u]) return l=st[u],r=ed[u],f=false,void(); int v=fath(rt,dep[rt]-dep[u]-1); l=st[v]-1,r=ed[v]+1,f=true; } int cntl[N],cntr[N],cntn[N];ll sum,h[N],ans[M]; void llht(int x){sum-=cntr[x],cntl[x]--;} void rrht(int x){sum+=cntl[x],cntr[x]++;} void lrht(int x){sum+=cntr[x],cntl[x]++;} void rlht(int x){sum-=cntl[x],cntr[x]--;} int main(){ n=read();int T=read(); for(int i=1;i<=n;i++)a[i]=b[i]=read(); sort(b+1,b+1+n),len=unique(b+1,b+1+n)-b-1; for(int i=1;i<=n;i++) a[i]=lower_bound(b+1,b+1+len,a[i])-b; for(int i=1,u,v;i<n;i++){ u=read(),v=read(); e[u].push_back(v),e[v].push_back(u); } dfs(1,0); for(int i=1;i<=n;i++)cntn[c[i]]++; for(int i=1;i<=n;i++) h[i]=h[i-1]+cntn[c[i]]; for(int opt,rt=1,u,v,l1,r1,l2,r2,f1,f2;T;T--){ opt=read(); if(opt==1){rt=read();continue;} u=read(),v=read(),m++; get(u,rt,l1,r1,f1),get(v,rt,l2,r2,f2); if(!f2)swap(u,v),swap(l1,l2),swap(r1,r2),swap(f1,f2); if(!f1&&!f2) ins(r1,r2,1),ins(l1-1,r2,-1),ins(r1,l2-1,-1),ins(l1-1,l2-1,1); else if(!f1){ ans[m]=h[r1]-h[l1-1]; ins(r1,l2,1),ins(l1-1,l2,-1),ins(r1,r2-1,-1),ins(l1-1,r2-1,1); } else{ ans[m]=h[n]+h[l2]+h[l1]-h[r1-1]-h[r2-1]; ins(l1,l2,1),ins(r1-1,l2,-1),ins(l1,r2-1,-1),ins(r1-1,r2-1,1); } } B=ceil(n/sqrt(tq)); sort(q+1,q+1+tq); for(int i=1,l=0,r=0;i<=tq;i++){ while(l>q[i].l)llht(c[l--]); while(r<q[i].r)rrht(c[++r]); while(l<q[i].l)lrht(c[++l]); while(r>q[i].r)rlht(c[r--]); ans[q[i].id]+=q[i].fl*sum; } for(int i=1;i<=m;i++) printf("%lld\n",ans[i]); return 0; }
本文作者:SE の 摆烂窝
本文链接:https://www.cnblogs.com/SError0819/p/18032918
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步