裸莫队,对于路劲上的查询直接树上莫队,没学过的人可以去写写bzoj的苹果树,子树查询用dfs序后用莫队处理。
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<vector>
#include<cmath>
#include<stack>
#include<string.h>
#define maxn 100005
using namespace std;
typedef long long LL;
int deap[maxn],vis[maxn],dis[maxn],kk[20][maxn];
int belong[maxn];
int size[maxn];
int ti[maxn];
int maxlog;
LL sum[maxn];
vector<int>g[maxn];
int cnt[maxn],r[maxn],tot;
int blo,block;
stack<int>st;
int to[maxn];
void init(int n){
maxlog=18;
blo=pow(n,2.0/3)/2;
block=0;
tot=0;
while (!st.empty()) {
st.pop();
}
for(int i=0;i<=n;i++){ g[i].clear();
vis[i]=ti[i]=0;
sum[i]=0;
}
}
void dfs(int v,int p,int d)
{
cnt[v]=++tot;
to[tot]=v;
size[v]=0;
deap[v]=d;
int i,k;
kk[0][v]=p;
for(i=1;i<maxlog;i++){
if(kk[i-1][v]<0)
kk[i][v]=-1;
else{
kk[i][v]=kk[i-1][kk[i-1][v]];
}
}
k=(int )g[v].size();
for(i=0;i<k;i++){
if(g[v][i]!=p){
dis[g[v][i]]=dis[v]+1;
dfs(g[v][i],v,d+1);
size[v]+=size[g[v][i]];
if(size[v]>=blo){
++block;
while(!st.empty()){
int p=st.top();
st.pop();
belong[p]=block;
}
size[v]=0;
}
}
}
st.push(v);
size[v]++;
r[v]=tot;
return ;
}
int find(int a,int b)
{
if(deap[a]>deap[b])
swap(a,b);
int i,f;
f=deap[b]-deap[a];
for(i=0;i<maxlog;i++)
{
if((f>>i)&1)
b=kk[i][b];
}
if(b==a)
return a;
for(i=maxlog-1;i>=0;i--)
{
if(kk[i][a]!=kk[i][b])
{
a=kk[i][a];
b=kk[i][b];
}
}
return kk[0][a];
}
struct pi{
int x,y;
int a,b;
int id;
}pp[maxn],pp1[maxn];
int cmp(pi a,pi b){
if(belong[a.x]!=belong[b.x]) return belong[a.x]<belong[b.x];
return belong[a.y]<belong[b.y];
}
int c[maxn];
int b[maxn];
int an;
void venxor(int u){
if(vis[u]){
sum[ti[c[u]]]-=b[c[u]];
ti[c[u]]--;
sum[ti[c[u]]]+=b[c[u]];
vis[u]=0;
}
else{
sum[ti[c[u]]]-=b[c[u]];
ti[c[u]]++;
sum[ti[c[u]]]+=b[c[u]];
vis[u]=1;
}
}
void mov(int u,int v){
if(deap[u]<deap[v]) swap(u,v);
while(deap[u]>deap[v]){
venxor(u);
u=kk[0][u];
}
while(u!=v){
venxor(u);
venxor(v);
u=kk[0][u];
v=kk[0][v];
}
}
LL gcd(LL a,LL b){
if(b==0) return a;
return gcd(b,a%b);
}
LL ans[maxn];
int cmp1(pi a,pi b){
if(belong[a.x]!=belong[b.x]) return belong[a.x]<belong[b.x];
return a.y<b.y;
}
template <class T>
inline void scan_d(T &ret) {
char c; ret=0;
while((c=getchar())<'0'||c>'9');
while(c>='0'&&c<='9') ret=ret*10+(c-'0'),c=getchar();
}
char s[35];
void print(LL x)
{
int con=0;
do
{
s[con++]=x%10+'0';
x/=10;
}while(x);
for(int i=con-1;i>=0;--i)putchar(s[i]);
printf("\n");
}
int main()
{
int t,n,m,N=0;
scan_d(t);
while (t--) {
scan_d(n);
scan_d(m);
init(n);
for(int i=1;i<=n;i++){
scan_d(c[i]);
b[i]=c[i];
}
sort(b+1,b+1+n);
for(int i=1;i<=n;i++) c[i]=lower_bound(b+1,b+1+n,c[i])-b;
for(int i=1;i<n;i++){
int x,y;
scan_d(x);
scan_d(y);
g[x].push_back(y);
g[y].push_back(x);
}
dfs(1,-1,0);
int x=0,y=0;
for(int i=0;i<m;i++){
int p;
scan_d(p);
if(p==1){
scan_d(pp[x].x);
scan_d(pp[x].y);
scan_d(pp[x].a);
scan_d(pp[x].b);
int w=pp[x].x;
pp[x].x=cnt[w];
pp[x].y=r[w];
pp[x].id=i;
x++;
}
else{
scan_d(pp1[y].x);
scan_d(pp1[y].y);
scan_d(pp1[y].a);
scan_d(pp1[y].b);
pp1[y].id=i;
y++;
}
}
sort(pp1,pp1+y,cmp);
for(int i=0;i<y;i++){
if(i==0){
mov(pp1[i].x,pp1[i].y);
}
else{
mov(pp1[i-1].x,pp1[i].x);
mov(pp1[i-1].y,pp1[i].y);
}
int w=find(pp1[i].x,pp1[i].y);
venxor(w);
ans[pp1[i].id]=gcd(sum[pp1[i].a],sum[pp1[i].b]);
venxor(w);
}
blo=sqrt(n);
int no=0;
for(int i=1;i<=n;i++){
int p=i;
no++;
while(p<=n&&p-i<blo){
belong[p]=no;
p++;
}
i=p-1;
}
sort(pp,pp+x,cmp1);
for(int i=0;i<=n;i++){
sum[i]=0;
ti[i]=0;
}
for(int i=0;i<x;i++){
if(i==0){
for(int j=pp[i].x;j<=pp[i].y;j++){
int v=to[j];
sum[ti[c[v]]]-=b[c[v]];
ti[c[v]]++;
sum[ti[c[v]]]+=b[c[v]];
}
}
else{
if(pp[i].x<pp[i-1].x){
for(int j=pp[i-1].x-1;j>=pp[i].x;j--){
int v=to[j];
sum[ti[c[v]]]-=b[c[v]];
ti[c[v]]++;
sum[ti[c[v]]]+=b[c[v]];
}
}
if(pp[i].y>pp[i-1].y){
for(int j=pp[i-1].y+1;j<=pp[i].y;j++){
int v=to[j];
sum[ti[c[v]]]-=b[c[v]];
ti[c[v]]++;
sum[ti[c[v]]]+=b[c[v]];
}
}
if(pp[i].x>pp[i-1].x){
for(int j=pp[i-1].x;j<pp[i].x;j++){
int v=to[j];
sum[ti[c[v]]]-=b[c[v]];
ti[c[v]]--;
sum[ti[c[v]]]+=b[c[v]];
}
}
if(pp[i].y<pp[i-1].y){
for(int j=pp[i-1].y;j>pp[i].y;j--){
int v=to[j];
sum[ti[c[v]]]-=b[c[v]];
ti[c[v]]--;
sum[ti[c[v]]]+=b[c[v]];
}
}
}
ans[pp[i].id]=gcd(sum[pp[i].a],sum[pp[i].b]);
}
printf("Case #%d:\n",++N);
for(int i=0;i<m;i++) printf("%lld\n",ans[i]);
}
}