(弄了一个月的搬瓦工搭个梯子顺便搭个博客玩……不务正业)
As we all know, Zhu is the most powerful man. He has the infinite power to protest the world. We need more men like Zhu!
In Duoladuo, this place is like a tree. There are n points and n−1 edges. And the root is 1 . Each point can reach other points. Each point has a value a[i] named Zhu power.
Liao is a curious baby, he has m questions to ask Zhu. But now Zhu is busy, he wants you to help him answer Liao’s questions.
Liao’s question will be likeop u v a b
.
ifop
is1
, the u is equal to v . Liao wants to know the gcd of the sum of numbers thats appears a times and the sum of numbers that appears b times in subtree u .
ifop
is2
, Liao wants to know the gcd of the sum of numbers thats appears a times and the sum of numbers that appears b times on the path from u to v .
gcd is greatest common divisor.
notice: we can know gcd(x,0)=x .
In the first line contains a single positive integer T , indicating number of test case.
In the second line there are two numbers n,m . n is the size of Duoladuo. m is the number of Liao’s questions.
The next line contains n integers A1,A2,…AN , means the value of i point.
In the next n−1 line contains tow numbers u,v . It means there is a edge between point u and point v .
The next m lines will be the Liao’s question:
1 u v a b
2 u v a b
1≤T≤10,1≤n≤100000,1≤m≤100000,1≤op≤2,1≤u,v≤n,1≤a,b≤n,1≤Ai≤1000000000 .
For each case, output Case #i:. ( i is the number of the test case, from 1 to T ).
Then, you need to output the answer for every Liao’s questions.
1 5 5 1 2 4 1 2 1 2 2 3 3 4 4 5 1 1 1 1 1 1 1 1 1 2 2 1 5 1 1 2 1 5 1 2 2 1 1 2 2
Case #1: 4 1 4 1 0
对于操作1只要搞出来树的dfs序,每个询问对应一个连续区间,直接做序列莫队即可。
对于操作2就是树上莫队。
然后我按照之前的做法在搞出的括号序上跑莫队,T了。Baidu到一篇博客也说本地测10s,根本卡不过去。看了一下数据,后面五个点的莫队基本上都跑满了 n∗n‾√ 。本来 n 给的范围就很大了,然后对于这种专门构造数据卡某种算法的我也是无Fuck说。那种树分块的暂时还不会,以后学一下。
另外那篇博客说做两次常数大其实不然,想一下也是分开做复杂度更优。
下面就贴个一起做的代码吧,写的还算比较短,不过很丑也过不去就是了。
#include
#include
#include
#include
#include
using namespace std;
struct rec{
int id, col;
}arr[100010];
struct que{
int x, y, l, r, lca, a, b, id; long long ans;
};
int T, n, m, to[100010];
inline int rd(){
int a=0; char c=getchar();
while(!isdigit(c)) c=getchar();
while(isdigit(c)) (a*=10)+=c-'0', c=getchar();
return a;
}
// 离散化
void lis(){
sort(arr+1, arr+n+1, [](rec a, rec b){return a.colint t=1;
for(int i=1;i<=n;){
int p=arr[i].col; to[t]=p;
while(i<=n&&arr[i].col==p) arr[i++].col=t;
t++;
}
sort(arr+1, arr+n+1, [](rec a, rec b){return a.idlong long gcd(long long a, long long b){
if(!a) return b;
while(b)
a%=b, swap(a, b);
return a;
}
// 莫队
namespace mo{
que qs[100010];
int seq[200010], op[100010], ed[100010], ed2[100010], T, qpt, bk, bel[200010];
int cnt[100010], cnt2[100010]; long long sum[100010], sum2[100010];
bool ext[100010], u[200010];
void init(){
T=qpt=0;
memset(cnt, 0, sizeof cnt); memset(sum, 0, sizeof sum);
memset(cnt2, 0, sizeof cnt2); memset(sum2, 0, sizeof sum2);
memset(ext, 0, sizeof ext); memset(u, 0, sizeof u);
}
// 处理询问
void prework(){
bk=ceil(sqrt(T));
for(int i=0, t=0;ifor(int j=0;i+jfor(int i=0;iif(qs[i].lca){
if(qs[i].x==qs[i].y){
if(qs[i].a==1||qs[i].b==1) qs[i].ans=to[arr[qs[i].x].col];
else qs[i].ans=0;
continue;
}
if(op[qs[i].x]>op[qs[i].y]) swap(qs[i].x, qs[i].y);
if(qs[i].x==qs[i].lca) qs[i].l=op[qs[i].x]+1;
else qs[i].l=ed[qs[i].x];
qs[i].r=op[qs[i].y];
}
else
qs[i].l=op[qs[i].x], qs[i].r=ed[qs[i].x];
}
}
void inc(int ss){
if(!u[ss]) return; int p=seq[ss];
sum2[cnt2[arr[p].col]++]-=to[arr[p].col];
sum2[cnt2[arr[p].col]]+=to[arr[p].col];
}
void dec(int ss){
if(!u[ss]) return; int p=seq[ss];
sum2[cnt2[arr[p].col]--]-=to[arr[p].col];
sum2[cnt2[arr[p].col]]+=to[arr[p].col];
}
void tog(int p){
if(ext[p]) sum[cnt[arr[p].col]--]-=to[arr[p].col], sum[cnt[arr[p].col]]+=to[arr[p].col];
else sum[cnt[arr[p].col]++]-=to[arr[p].col], sum[cnt[arr[p].col]]+=to[arr[p].col];
ext[p]^=1;
}
void go(){
prework();
sort(qs, qs+qpt, [](que a, que b){return bel[a.l]==bel[b.l]?a.rint l=0, r=0; ext[1]=1; sum[1]=sum2[1]=to[arr[1].col]; cnt[arr[1].col]=cnt2[arr[1].col]=1;
for(int i=0;iwhile(lwhile(l>qs[i].l) tog(seq[--l]), inc(l);
while(rwhile(r>qs[i].r) tog(seq[r]), dec(r--);
if(qs[i].lca){
if(qs[i].x==qs[i].y) continue;
tog(qs[i].lca); qs[i].ans=gcd(sum[qs[i].a], sum[qs[i].b]);
tog(qs[i].lca);
}
else
qs[i].ans=gcd(sum2[qs[i].a], sum2[qs[i].b]);
}
sort(qs, qs+qpt, [](que a, que b){return a.idnamespace tree{
struct edge{
int to;
edge *next;
edge(int t, edge *n):to(t), next(n){}
edge(){}
}pool[200010], *g[100010];
int T, fa[100010], son[100010], siz[100010], top[100010], dep[100010];
void init(){
T=0; memset(son, 0, sizeof son);
memset(g, 0, sizeof g);
}
void addedge(int u, int v){
g[u]=&(pool[T++]=edge(v, g[u]));
g[v]=&(pool[T++]=edge(u, g[v]));
}
void dfs(int p){
siz[p]=1; mo::u[mo::T]=1; mo::seq[mo::op[p]=mo::T++]=p;
for(edge *t=g[p];t;t=t->next){
if(t->to==fa[p]) continue;
fa[t->to]=p; dep[t->to]=dep[p]+1;
dfs(t->to);
siz[p]+=siz[t->to];
if(siz[t->to]>siz[son[p]]) son[p]=t->to;
}
mo::seq[mo::ed[p]=mo::T++]=p;
}
void dfs2(int p, int t){
top[p]=t;
if(son[p]) dfs2(son[p], t);
for(edge *t=g[p];t;t=t->next){
if(t->to==fa[p]||t->to==son[p]) continue;
dfs2(t->to, t->to);
}
}
int lca(int u, int v){
while(top[u]!=top[v]){
if(dep[top[u]]else u=fa[top[u]];
}
return dep[u]// 处理询问
void rd(que &a){
a.lca=rd(); a.x=rd(), a.y=rd(); a.a=rd(), a.b=rd();
if(a.lca==1) a.lca=0;
else a.lca=tree::lca(a.x, a.y);
}
int main(){
T=rd();
for(int r=1;r<=T;r++){
printf("Case #%d:\n", r);
tree::init(); mo::init();
n=rd(), m=rd();
for(int i=1;i<=n;i++) arr[i].id=i, arr[i].col=rd();
lis();
for(int i=1;i1); tree::dfs2(1, 1);
for(int i=0;ifor(int i=0;iprintf("%lld\n", mo::qs[i].ans);
}
return 0;
}
希望多遇到良心出题人:)
不过也是自己菜。