CodeChef DGCD
You're given a tree on N vertices. Each vertex has a positive integer written on it, number on the ith vertex being vi. Your program must process two types of queries :
1. Find query represented by F u v : Find out gcdof all numbers on the unique path between vertices u and v in the tree (both inclusive).
2. Change query represented by C u v d : Add d to the number written on all vertices along the unique path between vertices u and v in the tree (both inclusive).
Input
First line of input contains an integer Ndenoting the size of the vertex set of the tree. Then follow N - 1 lines, ith of which contains two integers ai and bi denoting an edge between vertices ai and bi in the tree. After this follow N space separated integers in a single line denoting initial values vi at each of these nodes. Then follows a single integer Q on a line by itself, denoting the number of queries to follow. Then follow Q queries, each one on a line by itself. Each query is either a find query or a change query with format as given in problem statement. Note that all vertices are 0-based.
Output
For every find query, print the answer to that query in one line by itself.
Example
Input:
6
0 4
0 5
1 5
5 2
3 5
3 1 3 2 4 2
5
F 3 5
C 1 3 1
C 3 4 4
F 3 0
F 2 5 Output:
2
7
1
大致题意:给一棵树,每个点都有点权.现在有两种操作:1.将u到v的路径上的点的点权都加k. 2.求u到v的路径上的点的gcd.
分析:两个点之间的路径,很容易想到树链剖分.常见的套路用线段树维护,但是这样的话就不好处理区间加了.需要用到gcd的一个性质:
gcd(a,b,c,d......) = gcd(a,b-c,c-d,......).也就是说只需要知道首元素的值和差分后序列的gcd就可以了.因为差分过了,所以修改操作可以直接变成单点修改.在pushup的时候就能更新gcd.这样的话会有一个问题.差分修改一个区间的后继,在树上,一个点可能有多个子节点,那么它的后继是谁呢?很容易就能想到是重儿子,因为我们查询和修改每次都是从重链往上跳,用到的自然就是重儿子的值.那么整体的思路就是用线段树维护差分+区间修改+单点查询.
说起来挺容易的,其实写起来比较复杂.首先差分有可能将数变成负的,gcd求出来就可能是一个负数,解决方法就是在最后输出答案的时候加一个abs. 第二个就是这道题建树的时候因为是要建差分序列,所以要在第二次dfs的时候处理出每个id对应的值(见代码),再一个就是查询的时候可能会遇到空区间,要及时特判掉. 最坑的就是线段树的标记下传会T掉!这道题卡时卡的丧心病狂,正确的做法是将一路的标记直接加上,不下传.最好使用快读.
调了一天QAQ,不过最后终于卡着时过了.
#include <cstdio>
#include <cmath>
#include <cstring>
#include <iostream>
#include <algorithm> using namespace std; const int maxn = ; int n,q,head[maxn],to[maxn * ],nextt[maxn * ],tot = ,v[maxn];
int dep[maxn],sizee[maxn],top[maxn],cnt,son[maxn],id[maxn],idx[maxn],fa[maxn];
int c[maxn << ],tag[maxn << ],g[maxn << ],val[maxn]; inline int read()
{
int ans,f=;char ch;
while ((ch=getchar())<''||ch>'') if (ch=='-') f=-;ans=ch-'';
while ((ch=getchar())>=''&&ch<='') ans=ans*+ch-'';
return ans*f;
} int gcd(int a,int b)
{
if (!b)
return a;
return gcd(b,a % b);
} void add(int x,int y)
{
to[tot] = y;
nextt[tot] = head[x];
head[x] = tot++;
} void dfs(int u,int d,int from)
{
dep[u] = d;
sizee[u] = ;
fa[u] = from;
for (int i = head[u];i;i = nextt[i])
{
int v = to[i];
if (v == from)
continue;
dfs(v,d + ,u);
sizee[u] += sizee[v];
if (sizee[v] >= sizee[son[u]])
son[u] = v;
}
} void dfs2(int u,int topp)
{
top[u] = topp;
id[u] = ++cnt;
val[cnt] = v[u];
if (son[u])
dfs2(son[u],topp);
for (int i = head[u];i;i = nextt[i])
{
int v = to[i];
if (v == son[u] || v == fa[u])
continue;
dfs2(v,v);
}
} void pushup(int o)
{
g[o] = gcd(g[o * ],g[o * + ]);
} void build(int o,int l,int r)
{
if (l == r)
{
c[o] = val[l];
g[o] = val[l] - val[l - ];
return;
}
int mid = (l + r) >>;
build(o * ,l,mid);
build(o * + ,mid + ,r);
pushup(o);
} void update1(int o,int l,int r,int x,int y,int v) //权值区间修改
{
if (x <= l && r <= y)
{
c[o] += v;
return;
}
int mid = (l + r) >> ;
if (x <= mid)
update1(o * ,l,mid,x,y,v);
if (y > mid)
update1(o * + ,mid + ,r,x,y,v);
} void update2(int o,int l,int r,int cur,int v) //gcd单点修改
{
if (l == r)
{
g[o] += v;
return;
}
pushdown(o);
int mid = (l + r) >> ;
if (cur <= mid)
update2(o * ,l,mid,cur,v);
if (cur > mid)
update2(o * + ,mid + ,r,cur,v);
pushup(o);
} int query1(int o,int l,int r,int cur) //单点询问权值
{
if (l == r)
return c[o];
pushdown(o);
int mid = (l + r) >> ;
if (cur <= mid)
return c[o] + query1(o * ,l,mid,cur);
if (cur > mid)
return c[o] + query1(o * + ,mid + ,r,cur);
} int query2(int o,int l,int r,int x,int y) //询问区间gcd
{
if (x > y)
return ;
if (x <= l && r <= y)
return g[o];
pushdown(o);
int mid = (l + r) >> ,res = ;
if (x <= mid)
{
int t = query2(o * ,l,mid,x,y);
if (!res)
res = t;
}
if (y > mid)
{
int t = query2(o * + ,mid + ,r,x,y);
if (!res)
res = t;
else
res = gcd(res,t);
}
return res; } int solve1(int x,int y)
{
int ans = ;
while (top[x] != top[y])
{
if (dep[top[x]] < dep[top[y]])
swap(x,y);
ans = gcd(ans,query1(,,n,id[top[x]]));
ans = gcd(ans,query2(,,n,id[top[x]] + ,id[x]));
x = fa[top[x]];
}
if (dep[x] > dep[y])
swap(x,y);
ans = gcd(ans,query1(,,n,id[x]));
ans = gcd(ans,query2(,,n,id[x] + ,id[y]));
return abs(ans);
} void solve2(int x,int y,int d)
{
while (top[x] != top[y])
{
if (dep[top[x]] < dep[top[y]])
swap(x,y);
update1(,,n,id[top[x]],id[x],d);
update2(,,n,id[top[x]],d);
update2(,,n,id[x] + ,-d);
x = fa[top[x]];
}
if (dep[x] > dep[y])
swap(x,y);
update1(,,n,id[x],id[y],d);
update2(,,n,id[x],d);
update2(,,n,id[y] + ,-d);
} int main()
{
n = read();
for (int i = ; i < n; i++)
{
int u,v;
u = read(),v = read();
u++;
v++;
add(u,v);
add(v,u);
}
for (int i = ; i <= n; i++)
v[i] = read();
dfs(,,);
dfs2(,);
build(,,n);
q = read();
while (q--)
{
char s[];
int a,b,c;
scanf("%s",s);
if (s[] == 'F')
{
a = read();
b = read();
a++;
b++;
printf("%d\n",solve1(a,b));
}
else
{
a = read();
b = read();
c = read();
a++;
b++;
solve2(a,b,c);
}
} return ;
}
CodeChef DGCD的更多相关文章
- CodeChef DGCD Dynamic GCD
CodeChef题面 Time limit 210 ms Code length Limit //内存限制也不说一下,真是的-- 50000 B OS Linux Language limit C, ...
- scau 2015寒假训练
并不是很正规的.每个人自愿参与自愿退出,马哥找题(马哥超nice么么哒). 放假第一周与放假结束前一周 2015-01-26 http://acm.hust.edu.cn/vjudge/contest ...
- BZOJ 5028 小z的加油站
bzoj链接 Time limit 10000 ms Memory limit 262144 kB OS Linux 感想 树上动态gcd的第二题也好了. [x] BZOJ 2257 [JSOI200 ...
- 洛谷 P4571 BZOJ 2257 [JSOI2009]瓶子和燃料
bzoj题目链接 上面hint那里是选择第2个瓶子和第3个瓶子 Time limit 10000 ms Memory limit 131072 kB OS Linux Source Jsoi2009 ...
- CC DGCD:Dynamic GCD——题解
https://vjudge.net/problem/CodeChef-DGCD https://www.codechef.com/problems/DGCD 题目大意: 给一颗带点权的树,两个操作: ...
- 【BZOJ-3514】Codechef MARCH14 GERALD07加强版 LinkCutTree + 主席树
3514: Codechef MARCH14 GERALD07加强版 Time Limit: 60 Sec Memory Limit: 256 MBSubmit: 1288 Solved: 490 ...
- 【BZOJ4260】 Codechef REBXOR 可持久化Trie
看到异或就去想前缀和(⊙o⊙) 这个就是正反做一遍最大异或和更新答案 最大异或就是很经典的可持久化Trie,从高到低贪心 WA: val&(1<<(base-1))得到的并不直接是 ...
- codechef 两题
前面做了这场比赛,感觉题目不错,放上来. A题目:对于数组A[],求A[U]&A[V]的最大值,因为数据弱,很多人直接排序再俩俩比较就过了. 其实这道题类似百度之星资格赛第三题XOR SUM, ...
- codechef January Challenge 2014 Sereja and Graph
题目链接:http://www.codechef.com/JAN14/problems/SEAGRP [题意] 给n个点,m条边的无向图,判断是否有一种删边方案使得每个点的度恰好为1. [分析] 从结 ...
随机推荐
- [network]交换机中用户权限
LEVEL 0(访问级):可以执行用于网络诊断等功能的命令.包括ping.tracert.telnet等命令,执行该级别命令的结果不能被保存到配置文件中. LEVEL 1(监控级):可以执行用于系统维 ...
- 基于日志报警插件 elastalert 实现告警
1.官方http://elastalert.readthedocs.io/en/latest/ 2.报警规则示例 http://elastalert.readthedocs.io/en/latest/ ...
- conda环境管理
查看环境 conda env list 创建环境 conda create -n python36 python=3.6 进入环境 source activate python36 activate ...
- HTML5+Bootstrap 学习笔记 3
HTML5 aria-* and role aria是指Accessible Rich Internet Application.role的作用是描述一个非标准的tag的实际作用,而aria-*的作用 ...
- JavaScript变态题目
刚才发现的一些变态的 JavaScript 题目,做了一下,只对了一半,特此发到园子里,和友友们分享一下.这些题目都是针对 Ecmascript 第三版的,原题里面全部都是选择题,有备选答案,这里我把 ...
- 王者荣耀交流协会第四次Scrum立会
会议时间:2017年10月23号 18:00-18:28,时长28分钟. 会议地点:二食堂一楼第四个档口对着的靠路边的桌子. 立会内容: 1.小组成员汇报今日工作: 2.关于折线图与饼状图生成问题 ...
- “Hello World!”团队第六周的第二次会议
今天是我们团队“Hello World!”团队第六周召开的第二次会议.博客内容: 一.会议时间 二.会议地点 三.会议成员 四.会议内容 五.todo list 六.会议照片 七.燃尽图 八.代码 一 ...
- <<世界是数字的>>读书笔记
<世界是数字的>这本书是大学职业规划老师介绍个我读的,从着本中我学到了很多. 第一章,计算机里有什么.这个问题可以从两方面来看:逻辑上或者说功能上的组成,即每一部分是什么.做什么.怎样做. ...
- C#控制台应用程序
使用C#创建控制台应用程序的基本步骤: (1)创建项目: (2)编辑C#源代码: (3)编译运行: 例题:在控制台输出“Hello world!”. 第一步:文件→新建→项目:选择“项目类型”为Vis ...
- 关于解决乱码问题的一点探索之二(涉及Unicode(utf-16)和GBK)
在上篇日志中(链接),我们讨论了utf-8编码和GBK编码之间转化的乱码问题,这一篇我们讨论Unicode(utf-16编码方式)与GBK编码之间转换的乱码问题. 在Windows系统 ...