[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 ; }
相关文章推荐
- [HDU5828] Rikka with Sequence [2016 Multi-University Training Contest 8(2016多校联合训练8) 1008]
- [HDU5826] physics [2016 Multi-University Training Contest 8(2016多校联合训练8) 1006]
- [HDU5788] Level Up [2016 Multi-University Training Contest 5 1008 (2016多校联合训练5)]
- [HDU5764] After a Sleepless Night [2016 Multi-University Training Contest 4(2016多校联合训练4) B]
- [HDU5739] Fantasia [2016 Multi-University Training Contest 2(多校联合训练2) F]
- [HDU5756] Boss Bo [2016 Multi-University Training Contest 3(2016多校联合训练3) E]
- [HDU5727] Necklace [2016 Multi-University Training Contest 1(2016多校联合训练1) E]
- [HDU5741] Helter Skelter [2016 Multi-University Training Contest 2(2016多校联合训练2) H]
- HDOJ 5792 (2016多校联合训练 Training Contest 5) World is Exploding
- 2016 Multi-University Training Contest 8(2016多校训练第八场)1011
- 2016 Multi-University Training Contest 2(2016多校训练第二场)1009
- 2016 Multi-University Training Contest 4(2016多校训练第四场)1011
- 【2016多校训练4】Multi-University Training Contest 4
- HDOJ 5773 (2016多校联合训练 Training Contest 4) The All-purpose Zero
- 2016 多校 Multi-University Training Contest 5 Two
- 2015多校联合训练赛 hdu 5305 Friends 2015 Multi-University Training Contest 2 枚举+剪枝
- HDU 5347 MZL's chemistry (2015 Multi-University Training Contest 5 2015多校联合)
- 「2017 Multi-University Training Contest 7」2017多校训练7
- HDOJ 5738 (2016多校联合训练 Training Contest 2) Eureka
- HDOJ 5753 (2016多校联合训练 Training Contest 3) Permutation Bo