HDU 5957 Query on a graph

2016ACM/ICPC亚洲区沈阳站

题意

  • \(N(N \le 10^5)\)个点,\(N\)条边的连通图。
  • 有\(M \le 10^5\)操作:
  1. \(MODIFY\ u\ k\ d,k \le 2\):距离点\(u\)不超过\(k\)的点的权值都加上\(d\)。
  2. \(QUERY\ u\ k\):询问距离\(d\)不超过\(k\)的点权和。

思路

  • 图的形状时一个环和若干树枝构成。
  • 考虑\(k=1\)时,分两种情况讨论:
  1. \(u\)在环上,则需要累加环上相邻两点权值,以及树枝上深度为1的所有点的权值,并且这些点的bfs序是连续的,那么显然可以用线段树维护权值和。
  2. \(u\)不在环上时,累加父亲节点的权值以及树枝深度为1的点权。
  • 记\(Q1(u)\)表示距离\(u\)不超过1的权值和。
  • 当\(k=2\)时,树枝上距离为2的点的bfs序也是连续的,所以同样用线段树维护,若\(u\)不在环上,累加上\(Q1(f_u)-w_u\)即可;若\(u\)在环上,求出\(Q1(v_1)+Q1(v_2)-2w_u\),\(v_1、v_2\)表示换上与\(u\)相邻的点,显然\(u\)被重复计数两次。
  • 当环的长度分别为3、4时,\(Q1(v_1)、Q2(v_2)\)存在交集,需要扣除重复计数的值。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ul;
#define sz(x) ((int)(x).size())
#define rep(i,l,r) for(int i=(l),I=(r);i<I;++i)
//-------head-------
const int N = 1e5 + 7;
#define ls ((t)<<1)
#define rs ((t)<<1|1)
ll sum[N << 2], add[N << 2];
inline void up(int t) {
sum[t] = sum[ls] + sum[rs];
}
inline void down(int t, int l, int r) {
if (add[t] != 0) {
int m = (l + r) >> 1;
sum[ls] += add[t] * (m - l + 1), add[ls] += add[t];
sum[rs] += add[t] * (r - m), add[rs] += add[t];
add[t] = 0;
}
}
void build(int t, int l, int r) {
sum[t] = add[t] = 0;
if (l < r) {
int m = (l + r) >> 1;
build(ls, l, m), build(rs, m + 1, r);
}
}
inline void upd(int t, int l, int r, int L, int R, ll v) {
if (R < l || r < L || L > R)
return ;
if (L <= l && r <= R) {
sum[t] += (r - l + 1) * v, add[t] += v;
return ;
}
down(t, l, r);
int m = (l + r) >> 1;
upd(ls, l, m, L, R, v), upd(rs, m + 1, r, L, R, v);
up(t);
}
inline ll qry(int t, int l, int r, int L, int R) {
if (R < l || r < L || L > R)
return 0;
if (L <= l && r <= R)
return sum[t];
down(t, l, r);
int m = (l + r) >> 1;
ll ret = qry(ls, l, m, L, R) + qry(rs, m + 1, r, L, R);
up(t);
return ret;
}
int n, q, tot, f[N], pos[N], deg[N], L[N][3], R[N][3];
vector<int> cir, e[N];
void bfs() {
queue<int> que;
rep(i, 1, n + 1)
if (deg[i] == 1)
que.push(i);
while (!que.empty()) {
int u = que.front();
que.pop();
rep(i, 0, sz(e[u])) {
int v = e[u][i];
--deg[v];
if (deg[v] == 1)
que.push(v);
}
}
rep(i, 1, n + 1)
deg[i] = (deg[i] == 2);
cir.clear();
rep(i, 1, n + 1)
if (deg[i]) {
int u = i;
do {
rep(j, 0, sz(e[u])) {
int v = e[u][j];
if (deg[v] && (cir.empty() || v != cir.back())) {
pos[u] = sz(cir);
cir.push_back(u);
u = v;
break;
}
}
} while (u != i);
break;
}
}
int que[N];
void BFS(int s) {
int h = 0, t = 0;
que[t++] = s, f[s] = -1;
while (h < t) {
int u = que[h++];
L[u][0] = R[u][0] = ++tot;
L[u][1] = L[u][2] = n + 1, R[u][1] = R[u][2] = 0;
rep(i, 0, sz(e[u])) {
int v = e[u][i];
if (v == f[u] || deg[v])
continue;
f[v] = u, que[t++] = v;
}
}
for (int i = t - 1; i > 0; --i) {
int v = que[i];
int u = f[v];
L[u][1] = min(L[u][1], L[v][0]), R[u][1] = max(R[u][1], R[v][0]);
u = f[u];
if (u == -1)
continue;
L[u][2] = min(L[u][2], L[v][0]), R[u][2] = max(R[u][2], R[v][0]);
}
// printf("u = %d, ", u);
// rep(i, 0, 3) printf("(%d, %d) ", L[u][i], R[u][i]);puts("");
}
char op[20];
inline ll Q0(int u) {
return qry(1, 0, tot, L[u][0], R[u][0]);
}
inline ll Q1(int u) {
ll ans = Q0(u) + qry(1, 0, tot, L[u][1], R[u][1]);
if (deg[u]) {
ans += Q0(cir[(pos[u] + 1) % sz(cir)]);
ans += Q0(cir[(pos[u] - 1 + sz(cir)) % sz(cir)]);
} else {
ans += Q0(f[u]);
}
return ans;
}
inline void A0(int u, ll v) {
upd(1, 0, tot, L[u][0], R[u][0], v);
}
inline void A1(int u, ll v) {
A0(u, v), upd(1, 0, tot, L[u][1], R[u][1], v);
if (deg[u]) {
A0(cir[(pos[u] + 1) % sz(cir)], v);
A0(cir[(pos[u] - 1 + sz(cir)) % sz(cir)], v);
} else {
A0(f[u], v);
}
}
int main() {
int T;
scanf("%d", &T);
rep(cas, 0, T) {
scanf("%d", &n);
rep(i, 1, n + 1)
deg[i] = 0, e[i].clear();
rep(i, 0, n) {
int u, v;
scanf("%d%d", &u, &v);
++deg[u], ++deg[v];
e[u].push_back(v), e[v].push_back(u);
}
bfs();
tot = 0;
rep(i, 1, n + 1)
if (deg[i])
BFS(i);
build(1, 0, tot);
scanf("%d", &q);
rep(_q, 0, q) {
scanf(" %s", op);
if (op[0] == 'M') {
int u, k, d;
scanf("%d%d%d", &u, &k, &d);
if (k == 0) {
A0(u, d);
} else if (k == 1) {
A1(u, d);
} else if (k == 2) {
A0(u, d), upd(1, 0, tot, L[u][1], R[u][1], d), upd(1, 0, tot, L[u][2], R[u][2], d);
if (deg[u]) {
int v1 = cir[(pos[u] + 1) % sz(cir)];
int v2 = cir[(pos[u] - 1 + sz(cir)) % sz(cir)];
A1(v1, d), A1(v2, d), A0(u, -2 * d);
if (sz(cir) == 3) {
A0(v1, -d), A0(v2, -d);
} else if (sz(cir) == 4) {
A0(cir[(pos[u] + 2) % sz(cir)], -d);
}
} else {
A1(f[u], d), A0(u, -d);
}
}
} else {
int u, k;
scanf("%d%d", &u, &k);
ll ans = 0;
if (k == 0) {
ans = Q0(u);
} else if (k == 1) {
ans = Q1(u);
} else if(k == 2) {
ans = Q0(u) + qry(1, 0, tot, L[u][1], R[u][1]) + qry(1, 0, tot, L[u][2], R[u][2]);
if (deg[u]) {
int v1 = cir[(pos[u] + 1) % sz(cir)];
int v2 = cir[(pos[u] - 1 + sz(cir)) % sz(cir)];
ans += Q1(v1) + Q1(v2) - 2ll * Q0(u);
if (sz(cir) == 3) {
ans -= Q0(v1) + Q0(v2);
} else if (sz(cir) == 4) {
ans -= Q0(cir[(pos[u] + 2) % sz(cir)]);
}
} else {
ans += Q1(f[u]) - Q0(u);
}
}
printf("%lld\n", ans);
}
}
}
return 0;
}

HDU 5957 Query on a graph的更多相关文章

  1. HDU 5957 Query on a graph (拓扑 + bfs序 + 树剖 + 线段树)

    题意:一个图有n个点,n条边,定义D(u,v)为u到v的距离,S(u,k)为所有D(u,v)<=k的节点v的集合 有m次询问(0<=k<=2): 1 u k d:将集合S(u,k)的 ...

  2. HDU5957 Query on a graph(拓扑找环,BFS序,线段树更新,分类讨论)

    传送门:http://acm.hdu.edu.cn/showproblem.php?pid=5957 题意:D(u,v)是节点u和节点v之间的距离,S(u,v)是一系列满足D(u,x)<=k的点 ...

  3. 【HDU 3435】 A new Graph Game (KM|费用流)

    A new Graph Game Problem Description An undirected graph is a graph in which the nodes are connected ...

  4. HDU 2454 Degree Sequence of Graph G(Havel定理 推断一个简单图的存在)

    主题链接:pid=2454">http://acm.hdu.edu.cn/showproblem.php?pid=2454 Problem Description Wang Haiya ...

  5. HDU 6191 Query on A Tree(可持久化Trie+DFS序)

    Query on A Tree Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 132768/132768 K (Java/Othe ...

  6. HDU 4010 Query on The Trees (动态树)(Link-Cut-Tree)

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4010 题意; 先给你一棵树,有 \(4\) 种操作: 1.如果 \(x\) 和 \(y\) 不在同一 ...

  7. HDU 4010.Query on The Trees 解题报告

    题意: 给出一颗树,有4种操作: 1.如果x和y不在同一棵树上则在xy连边 2.如果x和y在同一棵树上并且x!=y则把x换为树根并把y和y的父亲分离 3.如果x和y在同一棵树上则x到y的路径上所有的点 ...

  8. 动态树(LCT):HDU 4010 Query on The Trees

    Query on The Trees Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65768/65768 K (Java/Othe ...

  9. HDU 4010 Query on The Trees(动态树)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4010 题意:一棵树,四种操作: (1)若x和y不在一棵树上,将x和y连边: (2)若x和y在一棵树上, ...

随机推荐

  1. Spring学习笔记之Bean的实例化

    一.bean的实例化方法有3种, 1.构造器实例化 2.静态工厂方法实例化 3.实例工厂方法实例化 二.用构造器来实例化 <bean id="ShunDao" class=& ...

  2. 每天学一点JAVA

    1.JAVA的反射机制 在运行时判断任意一个对象所属的类:在运行时构造任意一个类的对象:在运行时判断任意一个类所具有的成员变量和方法:在运行时调用任意一个对象的方法:生成动态代理. 2.关于ARRAY ...

  3. hashmap和hashtable,arraylist和vector的区别

    hashmap线程不安全,hashtable线程安全 hashmap允许使用 null 值和 null 键.(除了非同步和允许使用 null 之外,HashMap 类与 Hashtable 大致相同. ...

  4. objective-c strong导致内存泄漏简单案例

    例如: @interface Test:NSObject{ id __strong obj_; } -(void) setObject:(id __strong)obj; @end @implemen ...

  5. 关于resolve非泛型方法不能与类型实参一起使用

    今天mvc新建三层时,写到bll层中一直报下面的错误,检查了几遍赶脚并没有什么错.最后发现缺少一些引用. 如下面的图,少添加了下面的两个引用.Unity是微软模式与实践团队开发的一个轻量级.可扩展的依 ...

  6. 预编译 .pch文件

    如果工程导入了其他编程语言文件混编的时候   .pch文件会在程序开始的时候导入所有头文件,需要 '预编写命令' 区分编程语言的头文件. 下面报错就是因为工程导入了.c 文件   .pch全局导入了O ...

  7. WPF制作子窗体的弹出动画效果

    创建一个WPF应用程序WpfApplication1,新建个窗体DialogWin <Windowx:Class="WpfApplication1.DialogWin" xm ...

  8. $.noop()和$.map()函数

    最近在项目中发现$.noop()函数,因以前没使用过故查询下,现整理如下: jQuery.noop()函数是一个空函数,它什么也不做. 当某些时候你需要传入函数参数,而且希望它什么也不做的时候,你可以 ...

  9. Ubuntu安装Osmocom-BB一只猿多频点WEB脚本

    LAMP(Linux- Apache-MySQL-PHP)网站架构是目前国际流行的Web框架,该框架包括:Linux操作系统,Apache网络服务器,MySQL数据 库,Perl.PHP或者Pytho ...

  10. 【LeetCode OJ】Triangle

    Problem Link: http://oj.leetcode.com/problems/triangle/ Let R[][] be a 2D array where R[i][j] (j < ...