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. [分析] 从结 ...
随机推荐
- Leftmost Digit(数学)
Description Given a positive integer N, you should output the leftmost digit of N^N. Input The inp ...
- 第一次作业(homework-01)成绩公布
已收到博客名.github名的同学得分列表: 学号后三位 成绩(0-10) 215 8082 0132 5184 5027 7194 9.5157 7074 8195 6222 8158 6128 8 ...
- “Hello World!”团队第七次Scrum立会
"Hello world!"团队召开第七次Scrum立会.博客内容: 1.会议时间 2.会议成员 3.会议地点 4.会议内容 5.Todo list 6.会议照片 7.燃尽图 一. ...
- C++:默认初始化
一.什么是默认初始化 默认初始化,顾名思义,即为在定义变量时如果没有为其指定初始化值,则该变量会被C++编译器赋予默认的值.而变量被赋予的默认值到底是什么,则取决于变量的数据类型和变量的定义位置. 二 ...
- Java微笔记(8)
Java 中的包装类 Java 为每个基本数据类型都提供了一个包装类,这样就可以像操作对象那样来操作基本数据类型 基本类型和包装类之间的对应关系: 包装类主要提供了两大类方法: 将本类型和其他基本类型 ...
- css3浏览器私有属性前缀使用详解
什么是浏览器私有属性前缀 CSS3的浏览器私有属性前缀是一个浏览器生产商经常使用的一种方式.它暗示该CSS属性或规则尚未成为W3C标准的一部分. 以下是几种常用前缀 -webkit- -moz- -m ...
- css全局样式基础代码
body{ font-size:12px; font-family:"宋体",Arial, Helvetica, sans-serif;color:#363636;backgrou ...
- MySQL 忘记root密码怎么办
前言:记住如果忘记root密码,在启动MySQL的时候,跳过查询授权表就ok了. 对于RedHat 6 而言 (1)启动mysqld 进程时,为其使用:--skip-grant-tables --sk ...
- PAT L1 - 056 猜数字
https://pintia.cn/problem-sets/994805046380707840/problems/994805074646122496 一群人坐在一起,每人猜一个 100 以内的数 ...
- Windows连接Linux服务器中MySQL数据库-权限配置
问题描述 在Windows系统中安装了监控MySQL数据库服务器性能的工具Spotlight on MySQL,利用Spotlight连接Linux服务器中的MySQL,进行相关配置如下: 点击& ...