CS杯2021 E

最近霉运连连,微信消息no response搞得去蹭曾老师的球台vp,QQ因为某事炸号


E题主要是先树链剖分,然后像吉司机线段树那样对一些有规律的区间进行标记,减少操作数。

莫比乌斯函数打表发现最多加一次就可以到达的循环中或者直接对应的莫比乌斯函数值为0即:

code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
#include <bits/stdc++.h>

using namespace std;

using ll=long long;

ll n,q, a[(int)1e6+9],M,p[(int)4e6+9],dep[(int)1e5+9],sz[(int)1e5+9],top[(int)1e5+9],son[(int)1e5+9],f[(int)1e5+9],id[(int)1e5+9],cov[(int)1e5+9];
bitset<(int)5e6+900> vis;
int mu[(int)5e6+900],pr[(int)5e6+900],cnt,tot;

const int maxn=1e5+9;
struct Node{
int l,r,tag,cs;
ll v;
}tr[maxn<<2];
bitset<(maxn*4ll)> upd;

void build(int l,int r,int tot){
if(l==r){
tr[tot].v=a[cov[l]];
return ;
}
int mid=(l+r)>>1;
build(l,mid,tot<<1),build(mid+1,r,(tot<<1)|1);
tr[tot].v=tr[tot<<1].v+tr[(tot<<1)|1].v;
}

void update(int nl,int nr,int tot,int l,int r){
int mid=(nl+nr)>>1;
if(tr[tot].cs&&nl!=nr){
tr[tot<<1].v+=tr[tot<<1].tag*(tr[tot].cs&1?1ll:0ll),tr[tot<<1|1].v+=tr[tot<<1|1].tag*(tr[tot].cs&1?1ll:0ll);
tr[tot<<1].cs+=tr[tot].cs,tr[(tot<<1)|1].cs+=tr[tot].cs;
tr[tot<<1].tag*=(tr[tot].cs&1?-1ll:1ll),tr[tot<<1|1].tag*=(tr[tot].cs&1?-1ll:1ll);
tr[tot].cs=0;
}
if(upd[tot]&&l<=nl&&nr<=r){
tr[tot].cs+=1;
tr[tot].v+=tr[tot].tag,tr[tot].tag*=-1ll;
return ;
}
if(nl==nr){
tr[tot].v+=mu[tr[tot].v];
if(mu[tr[tot].v]==0){
upd[tot]=1,tr[tot].tag=0;
return;
}
ll nxt=tr[tot].v+mu[tr[tot].v],nnxt=nxt+mu[nxt];
if(nnxt==tr[tot].v){
upd[tot]=1;
tr[tot].tag=mu[tr[tot].v];
}
return ;
}
if(mid>=l)update(nl,mid,tot<<1,l,r);
if(mid<r)update(mid+1,nr,(tot<<1)|1,l,r);
tr[tot].v=tr[tot<<1].v+tr[(tot<<1)|1].v;
if(upd[tot<<1]&&upd[tot<<1|1]){
upd[tot]=1;
tr[tot].tag=tr[tot<<1].tag+tr[tot<<1|1].tag;
}
}

ll Sum(int nl,int nr,int tot,int l,int r){
ll mid=(nl+nr)>>1,res=0;
if(tr[tot].cs&&nl!=nr){
tr[tot<<1].v+=tr[tot<<1].tag*(tr[tot].cs&1?1ll:0ll),tr[tot<<1|1].v+=tr[tot<<1|1].tag*(tr[tot].cs&1?1ll:0ll);
tr[tot<<1].cs+=tr[tot].cs,tr[(tot<<1)|1].cs+=tr[tot].cs;
tr[tot<<1].tag*=(tr[tot].cs&1?-1ll:1ll),tr[tot<<1|1].tag*=(tr[tot].cs&1?-1ll:1ll);
tr[tot].cs=0;
}
if(l<=nl&&nr<=r)return tr[tot].v;
if(mid>=l)res+=Sum(nl,mid,tot<<1,l,r);
if(mid<r)res+=Sum(mid+1,nr,(tot<<1)|1,l,r);
return res;
}

void get_mu()
{

mu[1]=1;
vis[1]=true;
for(int i=2;i<=5e6+10;i++)
{
if(!vis[i])
{
pr[++tot]=i;
vis[i]=true;
mu[i]=-1;
}
for(int j=1;j<=tot&&i*pr[j]<=5e6+10;j++)
{
vis[i*pr[j]]=true;
if(i%pr[j]==0)
{
mu[i*pr[j]]=0;
break;
}
else
{
mu[i*pr[j]]=-mu[i];
}
}
}
return ;
}

vector<int> g[(int)1e5+9];

void dfs1(int u,int fa,int deep){
dep[u]=deep,f[u]=fa,sz[u]=1;
int ma=0;
for(auto it:g[u]){
if(it!=fa){
dfs1(it,u,deep+1);
sz[u]+=sz[it];
if(ma<sz[it]){
ma=sz[it],son[u]=it;
}
}
}
}

void dfs2(int u,int fa){
top[u]=fa,id[u]=++cnt,cov[id[u]]=u;
if(!son[u])return ;
dfs2(son[u],fa);
for(auto it:g[u]){
if(it!=son[u]&&it!=f[u]){
dfs2(it,it);
}
}

}

void add(int u,int v){
while(top[u]!=top[v]){
if(dep[top[u]]<dep[top[v]])swap(u,v);
update(1,n,1,id[top[u]],id[u]);
u=f[top[u]];
}
if(dep[u]>dep[v])swap(u,v);
update(1,n,1,id[u],id[v]);
}

ll query(int u,int v){
ll res=0;
while(top[u]!=top[v]){
if(dep[top[u]]<dep[top[v]])swap(u,v);
res+=Sum(1,n,1,id[top[u]],id[u]);
u=f[top[u]];
}
if(dep[u]>dep[v])swap(u,v);
res+=Sum(1,n,1,id[u],id[v]);
return res;
}


int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
get_mu();
cin>>n;
for(int i=1;i<=n;++i)cin>>a[i];
for(int i=2,x,y;i<=n;++i){
cin>>x>>y;
g[x].push_back(y),g[y].push_back(x);
}
dfs1(1,0,1);
dfs2(1,1);
build(1,n,1);
cin>>q;
for(int i=1,x,y,z;i<=q;++i){
cin>>x>>y>>z;
if(x&1){
add(y,z);
}else cout<<query(y,z)<<"\n";
}
return 0;
}