您的位置:首页 > 大数据 > 人工智能

[HDU5799] This world need more Zhu [2016 Multi-University Training Contest 6(2016多校联合训练2) 1007]

2016-08-05 22:59 453 查看

题意

给定一棵树,n个节点,每个节点有个权值。

询问:

子树u中出现a次的权值的和与出现b次的权值的和的gcd

链(u,v)中出现a次的权值的和与出现b次的权值的和的gcd

有些绕,总之是每次询问的两个数字的gcd

题解

首先对权值进行离散化。

考虑子树询问 经典的莫队分块即可。具体实现为求dfs序,对询问排序,该子树区间左端点所在块为第一关键字,该子树区间右端点为第二关键字,然后查询。

考虑树链询问经典的树上莫队即可。具体实现为dfs分块,对询问排序,该树链左端点所在块为第一关键字,该树链右端点dfs序为第二关键字,然后查询。

才知道树上莫队有两种姿势,一种是我很早学的vfk的求LCA姿势,这个题也是这种姿势。另一种是std的姿势,不用求LCA,在move同时找到需要翻转的点。这样就除去了倍增LCA的复杂度,这个姿势有待学习研究。

代码

LCA版4336MS

/****************************************\
* Author : ztx
* Title  : This world need more Zhu 这个世界需要更多的^(* ̄(oo) ̄)^
* ALG    : 树上莫队+dfs序莫队分块
* CMT    : 似乎树上莫队有两种姿势,今天写的vfk的LCA版,然而还有一个std的更优的姿势待研究
* Time   :
\****************************************/

#include <cstdio>
#define Rep(i,l,r) for(i=(l);i<=(r);i++)
#define rep(i,l,r) for(i=(l);i< (r);i++)
#define Rev(i,r,l) for(i=(r);i>=(l);i--)
#define rev(i,r,l) for(i=(r);i> (l);i--)
typedef long long ll ;
typedef double lf ;
int CH , NEG ;
template <typename TP>inline void read(TP& ret) {
ret = NEG = 0 ; while (CH=getchar() , CH<'!') ;
if (CH == '-') NEG = true , CH = getchar() ;
while (ret = ret*10+CH-'0' , CH=getchar() , CH>'!') ;
if (NEG) ret = -ret ;
}
template <typename TP>inline void readc(TP& ret) {
while (ret=getchar() , ret<'!') ;
while (CH=getchar() , CH>'!') ;
}
template <typename TP>inline void reads(TP *ret) {
ret[0]=0;while (CH=getchar() , CH<'!') ;
while (ret[++ret[0]]=CH,CH=getchar(),CH>'!') ;
ret[ret[0]+1]=0;
}

#include <algorithm>
#include <cmath>
#include <cstring>

#define  maxn  100010LL
#define  maxm  100010LL

ll gcd(ll a,ll b) { return b ? gcd(b,a%b) : a ; }

int to[maxn<<1], nxt[maxn<<1], star[maxn], tote;
inline void AddEdge(int u,int v) {
tote ++ ; to[tote] = v; nxt[tote] = star[u]; star[u] = tote;
}

int n, m;
int col[maxn], dis[maxn], dis_cnt, newcol[maxn];

int sta[maxn], top = 0, idx, in[maxn], out[maxn], point[maxn], sz[maxn];
int szblc, blc_cnt, dep[maxn], fa[18][maxn], belong[maxn], lca[maxm];
ll sum[maxn], ans[maxn];
int cnt[maxn];
bool vis[maxn];

void dfs(int u,int fa) {
in[u] = ++ idx, point[idx] = u, dep[u] = dep[fa] + 1, ::fa[0][u] = fa, sz[u] = 0;
for (int p = star[u], v; v = to[p], p; p = nxt[p])
if (v != fa && (dfs(v,u), sz[u] += sz[v], sz[u] > szblc)) {
++ blc_cnt;
while (sz[u] -- ) belong[sta[top--]] = blc_cnt;
}
out[u] = idx, sta[++top] = u, sz[u] ++ ;
}

inline void ST() {
int i, k;
Rep (k,1,17) Rep (i,0,n)
fa[k][i] = fa[k-1][fa[k-1][i]] ;
}

inline int LCA(int u,int v) {
int k;
if (dep[u] < dep[v]) u ^= v, v ^= u, u ^= v;
Rev (k,17,0)
if (dep[fa[k][u]] >= dep[v]) u = fa[k][u];
if (u == v) return u;
Rev (k,17,0)
if (fa[k][u] != fa[k][v]) u = fa[k][u], v = fa[k][v];
return fa[0][u];
}

struct QUERY {
int l, r, belong, cmp, a, b, id, lca;
inline void set(int mode,int u,int v,int a,int b,int id) {
this->a = a, this->b = b, this->id = id;
if (mode&1) {
l = in[u], r = out[u], belong = in[u] / szblc, cmp = r;
} else {
if (u > v) u ^= v, v ^= u, u ^= v;
l = u, r = v, belong = ::belong[u], cmp = in[r];
lca = LCA(u,v);
}
}
bool operator < (const QUERY&B) const  {
if (belong == B.belong) return cmp < B.cmp; return belong < B.belong;
}
}qs[maxm], qc[maxm];
int cnt_s, cnt_c;

inline void Insert(int u) {
sum[cnt[newcol[u]]] -= col[u], sum[++cnt[newcol[u]]] += col[u];
}

inline void Erase(int u) {
sum[cnt[newcol[u]]] -= col[u], sum[--cnt[newcol[u]]] += col[u];
}

inline void Reverse(int u) {
if (!vis[u]) { vis[u] = true; Insert(u); }
else { vis[u] = false; Erase(u); }
}

inline void MoveTo(int u,int v) {
if (dep[u] < dep[v]) u ^= v, v ^= u, u ^= v;
while (dep[u] > dep[v]) Reverse(u), u = fa[0][u];
while (u != v)
Reverse(u), Reverse(v), u = fa[0][u], v = fa[0][v];
}

inline void GetAns(int i) {
Reverse(qc[i].lca) ;
ans[qc[i].id] = gcd(sum[qc[i].a],sum[qc[i].b]);
Reverse(qc[i].lca) ;
}

int main() {
#define READ
#ifdef  READ
freopen("data.in" ,"r",stdin ) ;
freopen("me.out","w",stdout) ;
#endif
int T, kiss, i, mode, u, v, a, b, l, r;
for (read(T), kiss = 1;kiss <= T;kiss ++ ) {
printf("Case #%d:\n", kiss);
read(n), read(m);
szblc = 333LL;
/// read color
Rep (i,1,n)
read(col[i]), dis[i] = col[i];
/// discrete
std::sort(dis+1, dis+n+1);
dis_cnt = std::unique(dis+1,dis+n+1)-dis;
Rep (i,1,n)
newcol[i] = std::lower_bound(dis+1,dis+dis_cnt+1,col[i])-dis;
/// read edge
tote = 0;
memset(star, 0, sizeof star);
rep (i,1,n)
read(u), read(v), AddEdge(u,v), AddEdge(v,u);
/// dfs get tree's Modui Blocks
idx = blc_cnt = top = 0;
dep[0] = 0;
dfs(1,0);
blc_cnt ++ ;
while (top) belong[sta[top--]] = blc_cnt;
ST();
/// read query
cnt_s = cnt_c = 0;
Rep (i,1,m) {
read(mode), read(u), read(v), read(a), read(b);
if (mode&1) qs[++cnt_s].set(mode,u,v,a,b,i);
else qc[++cnt_c].set(mode,u,v,a,b,i);
}
std::sort(qs+1,qs+cnt_s+1);
std::sort(qc+1,qc+cnt_c+1);
/// query subtree
memset(cnt,0,sizeof cnt);
memset(sum,0,sizeof sum);
l = 1, r = 0;
Rep (i,1,cnt_s) {
while (l > qs[i].l) Insert(point[--l]);
while (r < qs[i].r) Insert(point[++r]);
while (l < qs[i].l) Erase(point[l++]);
while (r > qs[i].r) Erase(point[r--]);
ans[qs[i].id] = gcd(sum[qs[i].a],sum[qs[i].b]);
}
/// query chain
memset(cnt,0,sizeof cnt);
memset(sum,0,sizeof sum);
memset(vis,0,sizeof vis);
if (cnt_c)
MoveTo(l = qc[1].l,r = qc[1].r), GetAns(1) ;
Rep (i,2,cnt_c) {
MoveTo(l,qc[i].l), MoveTo(r,qc[i].r), GetAns(i);
l = qc[i].l, r = qc[i].r;
}
/// output
Rep (i,1,m) printf("%lld\n", ans[i]);
}
#ifdef  READ
fclose(stdin) ; fclose(stdout) ;
#else
getchar() ; getchar() ;
#endif
return 0 ;
}


std版2870MS

/****************************************\
* Author : ztx
* Title  : This world need more Zhu 这个世界需要更多的^(* ̄(oo) ̄)^
* ALG    : 树上莫队+dfs序莫队分块
* CMT    : 似乎树上莫队有两种姿势,今天写的vfk的LCA版,然而还有一个std的更优的姿势待研究
这是std姿势的
* Time   :
\****************************************/

#include <cstdio>
#define Rep(i,l,r) for(i=(l);i<=(r);i++)
#define rep(i,l,r) for(i=(l);i< (r);i++)
#define Rev(i,r,l) for(i=(r);i>=(l);i--)
#define rev(i,r,l) for(i=(r);i> (l);i--)
typedef long long ll ;
typedef double lf ;
int CH , NEG ;
template <typename TP>inline void read(TP& ret) {
ret = NEG = 0 ; while (CH=getchar() , CH<'!') ;
if (CH == '-') NEG = true , CH = getchar() ;
while (ret = ret*10+CH-'0' , CH=getchar() , CH>'!') ;
if (NEG) ret = -ret ;
}
template <typename TP>inline void readc(TP& ret) {
while (ret=getchar() , ret<'!') ;
while (CH=getchar() , CH>'!') ;
}
template <typename TP>inline void reads(TP *ret) {
ret[0]=0;while (CH=getchar() , CH<'!') ;
while (ret[++ret[0]]=CH,CH=getchar(),CH>'!') ;
ret[ret[0]+1]=0;
}

#include <algorithm>
#include <cmath>
#include <cstring>

#define  maxn  100010LL
#define  maxm  100010LL

ll gcd(ll a,ll b) { return b ? gcd(b,a%b) : a ; }

int to[maxn<<1], nxt[maxn<<1], star[maxn], tote;
inline void AddEdge(int u,int v) {
tote ++ ; to[tote] = v; nxt[tote] = star[u]; star[u] = tote;
}

int n, m;
int col[maxn], dis[maxn], dis_cnt, newcol[maxn];

int sta[maxn], top = 0, idx, in[maxn], out[maxn], point[maxn], sz[maxn];
int szblc, blc_cnt, dep[maxn], fa[maxn], belong[maxn];
ll sum[maxn], ans[maxn];
int cnt[maxn];
bool vis[maxn];

void dfs(int u,int fa) {
in[u] = ++ idx, point[idx] = u, dep[u] = dep[fa] + 1, ::fa[u] = fa, sz[u] = 0;
for (int p = star[u], v; v = to[p], p; p = nxt[p])
if (v != fa && (dfs(v,u), sz[u] += sz[v], sz[u] > szblc)) {
++ blc_cnt;
while (sz[u] -- ) belong[sta[top--]] = blc_cnt;
}
out[u] = idx, sta[++top] = u, sz[u] ++ ;
}

struct QUERY {
int l, r, belong, cmp, a, b, id;
inline void set(int mode,int u,int v,int a,int b,int id) {
this->a = a, this->b = b, this->id = id;
if (mode&1) {
l = in[u], r = out[u], belong = in[u] / szblc, cmp = r;
} else {
if (u > v) u ^= v, v ^= u, u ^= v;
l = u, r = v, belong = ::belong[u], cmp = in[r];
}
}
bool operator < (const QUERY&B) const  {
if (belong == B.belong) return cmp < B.cmp; return belong < B.belong;
}
}qs[maxm], qc[maxm];
int cnt_s, cnt_c;

inline void Insert(int u) {
sum[cnt[newcol[u]]] -= col[u], sum[++cnt[newcol[u]]] += col[u];
}

inline void Erase(int u) {
sum[cnt[newcol[u]]] -= col[u], sum[--cnt[newcol[u]]] += col[u];
}

inline void Reverse(int u) {
if (!vis[u]) { vis[u] = true; Insert(u); }
else { vis[u] = false; Erase(u); }
}

int cross;

inline void MoveUp(int&u) {
if (!cross) {
if (vis[u] && !vis[fa[u]]) cross = u;
else if (!vis[u] && vis[fa[u]]) cross = fa[u];
}
Reverse(u), u = fa[u];
}

inline void MoveTo(int u,int newu) {
if (u == newu) return ;
cross = 0;
if (vis[newu]) cross = newu;
while (dep[u] > dep[newu]) MoveUp(u);
while (dep[newu] > dep[u]) MoveUp(newu);
while (u != newu) MoveUp(u), MoveUp(newu);
Reverse(u), Reverse(cross);
}

int main() {
#define READ
#ifdef  READ
freopen("data.in" ,"r",stdin ) ;
freopen("me.out","w",stdout) ;
#endif
int T, kiss, i, mode, u, v, a, b, l, r;
for (read(T), kiss = 1;kiss <= T;kiss ++ ) {
printf("Case #%d:\n", kiss);
read(n), read(m);
szblc = 333LL;
/// read color
Rep (i,1,n)
read(col[i]), dis[i] = col[i];
/// discrete
std::sort(dis+1, dis+n+1);
dis_cnt = std::unique(dis+1,dis+n+1)-dis;
Rep (i,1,n)
newcol[i] = std::lower_bound(dis+1,dis+dis_cnt+1,col[i])-dis;
/// read edge
tote = 0;
memset(star, 0, sizeof star);
rep (i,1,n)
read(u), read(v), AddEdge(u,v), AddEdge(v,u);
/// dfs get tree's Modui Blocks
idx = blc_cnt = top = 0;
dep[0] = 0;
dfs(1,0);
blc_cnt ++ ;
while (top) belong[sta[top--]] = blc_cnt;
/// read query
cnt_s = cnt_c = 0;
Rep (i,1,m) {
read(mode), read(u), read(v), read(a), read(b);
if (mode&1) qs[++cnt_s].set(mode,u,v,a,b,i);
else qc[++cnt_c].set(mode,u,v,a,b,i);
}
std::sort(qs+1,qs+cnt_s+1);
std::sort(qc+1,qc+cnt_c+1);
/// query subtree
memset(cnt,0,sizeof cnt);
memset(sum,0,sizeof sum);
l = 1, r = 0;
Rep (i,1,cnt_s) {
while (l > qs[i].l) Insert(point[--l]);
while (r < qs[i].r) Insert(point[++r]);
while (l < qs[i].l) Erase(point[l++]);
while (r > qs[i].r) Erase(point[r--]);
ans[qs[i].id] = gcd(sum[qs[i].a],sum[qs[i].b]);
}
/// query chain
memset(cnt,0,sizeof cnt);
memset(sum,0,sizeof sum);
memset(vis,0,sizeof vis);
l = r = 1;
Reverse(1);
Rep (i,1,cnt_c) {
MoveTo(l,qc[i].l), MoveTo(r,qc[i].r);
l = qc[i].l, r = qc[i].r;
ans[qc[i].id]=gcd(sum[qc[i].a],sum[qc[i].b]);
}
/// output
Rep (i,1,m) printf("%lld\n", ans[i]);
}
#ifdef  READ
fclose(stdin) ; fclose(stdout) ;
#else
getchar() ; getchar() ;
#endif
return 0 ;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐