(弄了一个月的搬瓦工搭个梯子顺便搭个博客玩……不务正业)
题目描述
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 andn−1 edges. And the root is 1 . Each point can reach other points. Each point has a valuea[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
, theu is equal to v . Liao wants to know thegcd of the sum of numbers thats appears a times and the sum of numbers that appearsb times in subtree u .
ifop
is2
, Liao wants to know thegcd of the sum of numbers thats appears a times and the sum of numbers that appearsb times on the path from u tov .
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 numbersn,m . n is the size of Duoladuo.m is the number of Liao’s questions.
The next line contains n integersA1,A2,…AN , means the value of i point.
In the nextn−1 line contains tow numbers u,v . It means there is a edge between point u and pointv .
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,根本卡不过去。看了一下数据,后面五个点的莫队基本上都跑满了
另外那篇博客说做两次常数大其实不然,想一下也是分开做复杂度更优。
下面就贴个一起做的代码吧,写的还算比较短,不过很丑也过不去就是了。
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
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.col<b.col;});
int 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.id<b.id;});
}
long 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;i<T;i+=bk, t++)
for(int j=0;i+j<T&&j<bk;j++)
bel[i+j]=t;
for(int i=0;i<qpt;i++){
if(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.r<b.r:bel[a.l]<bel[b.l];});
int 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;i<qpt;i++){
while(l<qs[i].l) tog(seq[l]), dec(l++);
while(l>qs[i].l) tog(seq[--l]), inc(l);
while(r<qs[i].r) tog(seq[++r]), inc(r);
while(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.id<b.id;});
}
}
namespace 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]]<dep[top[v]]) v=fa[top[v]];
else u=fa[top[u]];
}
return dep[u]<dep[v]?u:v;
}
}
// 处理询问
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;i<n;i++) tree::addedge(rd(), rd());
tree::dfs(1); tree::dfs2(1, 1);
for(int i=0;i<m;i++)
rd(mo::qs[mo::qpt]), mo::qs[mo::qpt++].id=i;
mo::go();
for(int i=0;i<m;i++)
printf("%lld\n", mo::qs[i].ans);
}
return 0;
}
希望多遇到良心出题人:)
不过也是自己菜。