洛谷P4689 [Ynoi2016]这是我自己的发明 [莫队]
ynoi中比较良心不卡常的题。
思路
没有换根操作时显然可以变成dfs序莫队随便搞。
换根操作时一个子树可以变成两段区间的并集,也随便搞搞就好了。
这题完全不卡常,随便过。
代码
#include<bits/stdc++.h>
clock_t t=clock();
namespace my_std{
using namespace std;
#define pii pair<int,int>
#define fir first
#define sec second
#define MP make_pair
#define rep(i,x,y) for (int i=(x);i<=(y);i++)
#define drep(i,x,y) for (int i=(x);i>=(y);i--)
#define go(x) for (int i=head[x];i;i=edge[i].nxt)
#define templ template<typename T>
#define sz 505050
typedef long long ll;
typedef double db;
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
templ inline T rnd(T l,T r) {return uniform_int_distribution<T>(l,r)(rng);}
templ inline bool chkmax(T &x,T y){return x<y?x=y,1:0;}
templ inline bool chkmin(T &x,T y){return x>y?x=y,1:0;}
templ inline void read(T& t)
{
t=0;char f=0,ch=getchar();double d=0.1;
while(ch>'9'||ch<'0') f|=(ch=='-'),ch=getchar();
while(ch<='9'&&ch>='0') t=t*10+ch-48,ch=getchar();
if(ch=='.'){ch=getchar();while(ch<='9'&&ch>='0') t+=d*(ch^48),d*=0.1,ch=getchar();}
t=(f?-t:t);
}
template<typename T,typename... Args>inline void read(T& t,Args&... args){read(t); read(args...);}
char sr[1<<21],z[20];int C=-1,Z=0;
inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
inline void print(register int x)
{
if(C>1<<20)Ot();if(x<0)sr[++C]='-',x=-x;
while(z[++Z]=x%10+48,x/=10);
while(sr[++C]=z[Z],--Z);sr[++C]='\n';
}
void file()
{
#ifndef ONLINE_JUDGE
freopen("a.in","r",stdin);
#endif
}
inline void chktime()
{
#ifndef ONLINE_JUDGE
cout<<(clock()-t)/1000.0<<'\n';
#endif
}
#ifdef mod
ll ksm(ll x,int y){ll ret=1;for (;y;y>>=1,x=x*x%mod) if (y&1) ret=ret*x%mod;return ret;}
ll inv(ll x){return ksm(x,mod-2);}
#else
ll ksm(ll x,int y){ll ret=1;for (;y;y>>=1,x=x*x) if (y&1) ret=ret*x;return ret;}
#endif
// inline ll mul(ll a,ll b){ll d=(ll)(a*(double)b/mod+0.5);ll ret=a*b-d*mod;if (ret<0) ret+=mod;return ret;}
}
using namespace my_std;
int n,m;
int w[sz],ww[sz],a[sz];
struct E{int t,nxt;}edge[sz<<1];
int head[sz],ecnt;
void make_edge(int f,int t)
{
edge[++ecnt]=(E){t,head[f]};
head[f]=ecnt;
edge[++ecnt]=(E){f,head[t]};
head[t]=ecnt;
}
int dep[sz],dfn[sz],low[sz],fa[sz][25],T;
#define v edge[i].t
void dfs(int x,int f)
{
dfn[x]=++T;a[T]=w[x];fa[x][0]=f;dep[x]=dep[f]+1;
rep(i,1,20) fa[x][i]=fa[fa[x][i-1]][i-1];
go(x) if (v!=f) dfs(v,x);
low[x]=T;
}
#undef v
int jump(int x,int to)
{
drep(i,20,0)
if (fa[x][i]&&dep[fa[x][i]]>dep[to])
x=fa[x][i];
return x;
}
struct hhh
{
int l1,r1,l2,r2,id;
hhh(int ll1=0,int rr1=0,int ll2=0,int rr2=0,int idd=0){l1=ll1,r1=rr1,l2=ll2,r2=rr2,id=idd;}
}qq[sz<<2];
int pos[sz],blo;
void init(){blo=sqrt(n);rep(i,0,n) pos[i]=i/blo;}
struct hh{int a,b,id,p;}q[sz<<4];
inline bool cmp(const hh &x,const hh &y){return pos[x.a]==pos[y.a]?((pos[x.a]&1)?x.b<y.b:x.b>y.b):pos[x.a]<pos[y.a];}
ll Ans[sz];
int cnta[sz],cntb[sz];
ll ans;
void solve(int m)
{
int l1,r1,l2,r2,id,M=0;
rep(i,1,m)
{
l1=qq[i].l1,r1=qq[i].r1,l2=qq[i].l2,r2=qq[i].r2,id=qq[i].id;
if (l1>r1||l2>r2||!r1||!r2) continue;
if (l1-1&&l2-1) q[++M]=(hh){l1-1,l2-1,id,1};
if (l1-1) q[++M]=(hh){l1-1,r2,id,-1};
if (l2-1) q[++M]=(hh){r1,l2-1,id,-1};
q[++M]=(hh){r1,r2,id,1};
}
init();
sort(q+1,q+M+1,cmp);
int A=0,B=0;
rep(i,1,M)
{
while (A<q[i].a) ++A,++cnta[a[A]],ans+=cntb[a[A]];
while (A>q[i].a) ans-=cntb[a[A]],--cnta[a[A]],--A;
while (B<q[i].b) ++B,++cntb[a[B]],ans+=cnta[a[B]];
while (B>q[i].b) ans-=cnta[a[B]],--cntb[a[B]],--B;
Ans[q[i].id]+=ans*q[i].p;
}
}
int main()
{
file();
int x,y,z,rt=1;
read(n,m);
rep(i,1,n) read(w[i]),ww[i]=w[i];
sort(ww+1,ww+n+1);unique(ww+1,ww+n+1);
rep(i,1,n) w[i]=lower_bound(ww+1,ww+n+1,w[i])-ww;
rep(i,1,n-1) read(x,y),make_edge(x,y);
dfs(1,0);
int M=0,c=0;
rep(i,1,m)
{
read(z);
if (z==1) { read(rt); continue; }
read(x,y);++c;
#define in(x) dfn[x]<=dfn[rt]&&dfn[rt]<=low[x]
if (in(y)) swap(x,y);
if (rt==x)
{
if (rt==y) qq[++M]=hhh(1,n,1,n,c);
else if (in(y)) z=jump(rt,y),qq[++M]=hhh(1,n,1,dfn[z]-1,c),qq[++M]=hhh(1,n,low[z]+1,n,c);
else qq[++M]=hhh(1,n,dfn[y],low[y],c);
}
else if (in(x))
{
z=jump(rt,x);int zz;
if (rt==y) qq[++M]=hhh(1,n,1,dfn[z]-1,c),qq[++M]=hhh(1,n,low[z]+1,n,c);
else if (in(y))
zz=jump(rt,y),
qq[++M]=hhh(1,dfn[z]-1,1,dfn[zz]-1,c),qq[++M]=hhh(1,dfn[z]-1,low[zz]+1,n,c),
qq[++M]=hhh(low[z]+1,n,1,dfn[zz]-1,c),qq[++M]=hhh(low[z]+1,n,low[zz]+1,n,c);
else qq[++M]=hhh(dfn[y],low[y],1,dfn[z]-1,c),qq[++M]=hhh(dfn[y],low[y],low[z]+1,n,c);
}
else qq[++M]=hhh(dfn[x],low[x],dfn[y],low[y],c);
#undef in
}
solve(M);
rep(i,1,c) printf("%lld\n",Ans[i]);
return 0;
}