传送门:http://acm.hdu.edu.cn/showproblem.php?pid=5957

题意:D(u,v)是节点u和节点v之间的距离,S(u,v)是一系列满足D(u,x)<=k的点的集合,操作1:将S(u,k)内节点权值增加或者减小,操作2:查询S(u,k)内节点的权值和

题解:因为题目说了查询和更新的距离小于等于k,k最大为2,所以很显然要分情况讨论k为0、1、2的情况

因为是多次更新,我们显然是需要用线段树来维护节点权值的

运用线段树和bfs序的知识我们知道

对一个棵树求BFS序后,深度相同的节点的序号是相邻的。
对于节点u,如果知道它儿子的最小BFS序号L和最大BFS序号R,那么它儿子的所有序号就在[L,R]中。

这样就比较方便对区间进行查询或者修改操作

根据题意可以知道:每次更新的时候

如果k==0,那么就只更新自己

如果k==1,那么就更新自己还有和自己相连的边,由于存在环的情况,所以我们要首先处理每个节点的入度,处理完入度的话,如果这个点的入度是1,那么证明这个点就不在环上,就更新他自己,他的儿子,他的父亲节点即可,如果这个点的入度大于1,那么这个点就在环上,稍微画个图就知道,环上就有左爸爸和右爸爸,将这两个节点给更新就好

如果k==2,那么情况就比较复杂了,首先是要更新自己,然后,和自己相连的边,和之前一样要判断环的情况,没有环的话,再讨论自己的爸爸节点还有儿子节点的情况,可能存在爸爸节点在环上、爸爸节点不在环上,儿子节点在环上、儿子节点不在环上,这样分类讨论完后即可

求和和更新差不多就不多讲了

代码有注释.

代码如下:

#include <map>
#include <set>
#include <cmath>
#include <ctime>
#include <stack>
#include <queue>
#include <cstdio>
#include <cctype>
#include <bitset>
#include <string>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <functional>
#define PI acos(-1)
#define eps 1e-8
#define fuck(x) cout<<#x<<" = "<<x<<endl;
#define FIN freopen("input.txt","r",stdin);
#define FOUT freopen("output.txt","w+",stdout);
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
//#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int maxn = 2e5 + ;
const int INF = 0x3f3f3f3f;
const int MOD = 1e9 + ;
LL gcd(LL a, LL b) {return b ? gcd(b, a % b) : a;}
LL lcm(LL a, LL b) {return a / gcd(a, b) * b;}
LL powmod(LL a, LL b, LL MOD) {LL ans = ; while (b) {if (b % )ans = ans * a % MOD; a = a * a % MOD; b /= ;} return ans;}
double dpow(double a, LL b) {double ans = 1.0; while (b) {if (b % )ans = ans * a; a = a * a; b /= ;} return ans;}
int n, q;
struct node {
int v, nxt, w;
} edge[maxn];
int head[maxn];
int tot;
void add_edge(int u, int v) {
edge[tot].v = v;
edge[tot].nxt = head[u];
head[u] = tot++;
} int in[maxn]; void top() {
queue<int>q;
for (int i = ; i <= n; i++) if (in[i] == ) q.push(i);
while (!q.empty()) {
int u = q.front(); q.pop();
for (int i = head[u]; ~i; i = edge[i].nxt) {
int v = edge[i].v;
if (in[v] > ) {
in[v]--;
if (in[v] == ) q.push(v);
}
}
}
} LL sum[maxn << ], add[maxn << ];
void build(int l, int r, int rt) {
sum[rt] = add[rt] = ;
if (l == r) return;
int m = (l + r) >> ;
build(lson);
build(rson);
}
void PushDown(int m, int rt) {
if (add[rt]) {
add[rt << ] += add[rt];
add[rt << | ] += add[rt];
sum[rt << ] += add[rt] * (m - (m >> ));
sum[rt << | ] += add[rt] * (m >> );
add[rt] = ;
}
}
void PushUP(int rt) {
sum[rt] = sum[rt << ] + sum[rt << | ];
}
void update(int L, int R, int c, int l, int r, int rt) {
if (L == || R == ) return;
if (L <= l && R >= r) {
sum[rt] += (LL)(r - l + ) * c;
add[rt] += c;
return;
}
PushDown(r - l + , rt);
int m = (l + r) >> ;
if (L <= m) update(L, R, c, lson);
if (R > m) update(L, R, c, rson);
PushUP(rt);
}
LL query(int L, int R, int l, int r, int rt) {
if (L == || R == ) return ;
if (L <= l && R >= r) return sum[rt];
PushDown(r - l + , rt);
int m = (l + r) >> ;
LL ret = ;
if (L <= m) ret += query(L, R, lson);
if (R > m) ret += query(L, R, rson);
PushUP(rt);
return ret;
}
int ver[maxn][]; int p[maxn], fp[maxn], fa[maxn], sz;
int sonL[maxn], sonR[maxn], ssonL[maxn], ssonR[maxn];
//设val[u]为节点u的权值,fa[u]为父亲,son[u]为儿子,sson[u]孙子
void bfs(int top) { //bfs序找最左和最右的区间
queue<int>q;
q.push(top);
while (!q.empty()) {
int u = q.front(); q.pop();
sonL[u] = ssonL[u] = INF;
sonR[u] = ssonR[u] = ;
for (int i = head[u]; i!=-; i = edge[i].nxt) {
int v = edge[i].v;
if (in[v] > || v == fa[u]) continue; //如果连的点在环上就不管
p[v] = ++sz; //继续打编号
fp[sz] = v;
fa[v] = u;
sonL[u] = min(sonL[u], p[v]);
sonR[u] = max(sonR[u], p[v]);
q.push(v);
}
ssonL[fa[u]] = min(ssonL[fa[u]], sonL[u]);
ssonR[fa[u]] = max(ssonR[fa[u]], sonR[u]);
}
} void change(int u, int k, int d) {
int father = fa[u];
//分类讨论
//如果k==0,那么就更新单个节点
//如果k==1,那么就更新u的儿子和爸爸还有自己
//1)需要讨论是否在环上,环上的话相当于有两个爸爸
//如果k==2,那么就更新u的儿子和孙子,u的爸爸和u的爷爷,还有自己
//1)需要讨论u是否在环上,环上的话,有两个爸爸和两个爷爷都要更新
//2)需要讨论u的儿子和孙子是否在环上
if (k == ) update(p[u], p[u], d, , n, );
else if (k == ) {
update(sonL[u], sonR[u], d, , n, );
update(p[u], p[u], d, , n, );
if (in[u] == ) update(p[fa[u]], p[fa[u]], d, , n, );
else {
update(p[ver[u][]], p[ver[u][]], d, , n, );
update(p[ver[u][]], p[ver[u][]], d, , n, );
}
} else if (k == ) {
//update(p[u],p[u],d,1,n,1);
update(sonL[u], sonR[u], d, , n, );
update(ssonL[u], ssonR[u], d, , n, );
if (in[u] == ) {
update(p[fa[u]], p[fa[u]], d, , n, );
update(sonL[fa[u]], sonR[fa[u]], d, , n, );
if (in[fa[u]] == ) {
update(p[fa[fa[u]]], p[fa[fa[u]]], d, , n, );
} else {
update(p[ver[fa[u]][]], p[ver[fa[u]][]], d, , n, );
update(p[ver[fa[u]][]], p[ver[fa[u]][]], d, , n, );
}
} else {
update(p[u], p[u], d, , n, );
int vv[];
int cnt = ;
for (int i = ; i < ; i++) {
int v = ver[u][i];
update(p[v], p[v], d, , n, );
update(sonL[v], sonR[v], d, , n, );
for (int j = ; j < ; j++) {
if (ver[v][j] == u || ver[v][j] == ver[u][] || ver[v][j] == ver[u][]) continue;
if (cnt > && ver[v][j] == vv[cnt - ]) continue;
vv[cnt++] = ver[v][j]; }
}
for (int i = ; i < cnt; i++) {
update(p[vv[i]], p[vv[i]], d, , n, );
}
}
}
}
int get_ans(int u, int k) {
//分类讨论
//如果k==0,那么就查询单个节点
//如果k==1,那么就查询u的儿子和爸爸还有自己
//1)需要讨论是否在环上,环上的话相当于有两个爸爸
//如果k==2,那么就查询u的儿子和孙子,u的爸爸和u的爷爷,还有自己
//1)需要讨论u是否在环上,环上的话,有两个爸爸和两个爷爷都要查询
//2)需要讨论u的儿子和孙子是否在环上
int ans = ;
if (k == ) ans += query(p[u], p[u], , n, );
else if (k == ) {
ans += query(sonL[u], sonR[u], , n, );
ans += query(p[u], p[u], , n, );
if (in[u] == ) ans += query(p[fa[u]], p[fa[u]], , n, );
else {
ans += query(p[ver[u][]], p[ver[u][]], , n, );
ans += query(p[ver[u][]], p[ver[u][]], , n, );
}
} else if (k == ) {
//update(p[u],p[u],d,1,n,1);
ans += query(sonL[u], sonR[u], , n, );
ans += query(ssonL[u], ssonR[u], , n, );
if (in[u] == ) {
ans += query(p[fa[u]], p[fa[u]], , n, );
ans += query(sonL[fa[u]], sonR[fa[u]], , n, );
if (in[fa[u]] == ) {
ans += query(p[fa[fa[u]]], p[fa[fa[u]]], , n, );
} else {
ans += query(p[ver[fa[u]][]], p[ver[fa[u]][]], , n, );
ans += query(p[ver[fa[u]][]], p[ver[fa[u]][]], , n, );
}
} else {
ans += query(p[u], p[u], , n, );
int vv[];
int cnt = ;
for (int i = ; i < ; i++) {
int v = ver[u][i];
ans += query(p[v], p[v], , n, );
ans += query(sonL[v], sonR[v], , n, );
for (int j = ; j < ; j++) {
if (ver[v][j] == u || ver[v][j] == ver[u][] || ver[v][j] == ver[u][]) continue;
if (cnt > && ver[v][j] == vv[cnt - ]) continue;
vv[cnt++] = ver[v][j];
}
}
for (int i = ; i < cnt; i++) {
ans += query(p[vv[i]], p[vv[i]], , n, );
}
}
}
return ans;
}
int main() {
#ifndef ONLINE_JUDGE
FIN
#endif
int T;
scanf("%d", &T);
while (T--) {
scanf("%d", &n);
for (int i = ; i <= n; i++) {
in[i] = ; fa[i] = ; head[i] = -;
}
tot = ;
sz=;
int u, v;
for (int i = ; i <= n; i++) {
scanf("%d%d", &u, &v);
in[v]++;
in[u]++;
add_edge(u, v);
add_edge(v, u);
}
top();
for (int u = ; u <= n; u++) {//遍历每一个节点
if (in[u] > ) {//如果节点的入度大于1
int j = ;
for (int i = head[u]; i!=-; i = edge[i].nxt) { //这个节点所有的子树
int v = edge[i].v;
if (in[v] > ) {//如果这个点在环上
ver[u][j++] = v;//记录点u在环上连的是哪两个点
}
}
p[u] = ++sz;//给点u编号
fp[sz] = u;
bfs(u);
}
}
build(, n, );
char op[];
int k, d;
scanf("%d", &q);
while (q--) {
scanf("%s", op);
if (op[] == 'M') {
scanf("%d%d%d", &u, &k, &d);
change(u, k, d);
} else {
scanf("%d%d", &u, &k);
printf("%d\n", get_ans(u, k));
}
}
}
}

HDU5957 Query on a graph(拓扑找环,BFS序,线段树更新,分类讨论)的更多相关文章

  1. 牛客练习赛11 假的字符串 (Trie树+拓扑找环)

    牛客练习赛11 假的字符串 (Trie树+拓扑找环) 链接:https://ac.nowcoder.com/acm/problem/15049 来源:牛客网 给定n个字符串,互不相等,你可以任意指定字 ...

  2. 【BZOJ-3832】Rally 拓扑序 + 线段树 (神思路题!)

    3832: [Poi2014]Rally Time Limit: 20 Sec  Memory Limit: 128 MBSec  Special JudgeSubmit: 168  Solved:  ...

  3. 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)的 ...

  4. POJ 2553 The Bottom of a Graph Tarjan找环缩点(题解解释输入)

    Description We will use the following (standard) definitions from graph theory. Let V be a nonempty ...

  5. S - Query on a tree HDU - 3804 线段树+dfs序

    S - Query on a tree HDU - 3804   离散化+权值线段树 题目大意:给你一棵树,让你求这棵树上询问的点到根节点直接最大小于等于val的长度. 这个题目和之前写的那个给你一棵 ...

  6. 【CodeForces】915 D. Almost Acyclic Graph 拓扑排序找环

    [题目]D. Almost Acyclic Graph [题意]给定n个点的有向图(无重边),问能否删除一条边使得全图无环.n<=500,m<=10^5. [算法]拓扑排序 [题解]找到一 ...

  7. HDU 5957 Query on a graph

    HDU 5957 Query on a graph 2016ACM/ICPC亚洲区沈阳站 题意 \(N(N \le 10^5)\)个点,\(N\)条边的连通图. 有\(M \le 10^5\)操作: ...

  8. E. Andrew and Taxi(二分+拓扑判环)

    题目链接:http://codeforces.com/contest/1100/problem/E 题目大意:给你n和m,n代表有n个城市,m代表有m条边,然后m行输入三个数,起点,终点,花费.,每一 ...

  9. Codeforces Beta Round #88 C. Cycle —— DFS(找环)

    题目链接:http://codeforces.com/problemset/problem/117/C C. Cycle time limit per test 2.5 seconds memory ...

随机推荐

  1. sqlalchemy 转json 的几种常用方式

    sqlalchemy 转json 的几种常用方式 # -*- coding:utf-8 -*- import datetime from flask import Flask, json, jsoni ...

  2. 解决ssh_exchange_identification:read connection reset by peer 原因

    服务器改了密码,试过密码多次后出现: ssh_exchange_identification: read: Connection reset by peer 可以通过ssh -v查看连接时详情 Ope ...

  3. 总结获取原生JS(javascript)基本操作

    var a = document.getElementByIdx_x_x("dom"); jsCopy(a);//调用清理空格的函数 var b = a.childNodes;// ...

  4. 应用Response.Write实现带有进度条的多文件上传

    前几天,写过一篇随笔“使用RESPONSE.WRITE实现在页面的生命周期中前后台的交互”.说是交互,实际上也主要是在ASP.NET的页面周期中 从后台利用RESPONSE.WRITE向前台即时的推送 ...

  5. Python高级编程-itertoos模块

    Python的内建模块itertools提供了非常有用的用于操作迭代对象的函数. 首先我们看看itertools模块提供的几个“无限”迭代器, import itertools naturals = ...

  6. 20145214 《Java程序设计》第6周学习总结

    20145214 <Java程序设计>第6周学习总结 教材学习内容总结 串流设计 Java将输入/输出抽象化为串流,数据有来源及目的地,衔接两者的是串流对象. 输入串流代表对象为java. ...

  7. LintCode-165.合并两个排序链表

    合并两个排序链表 将两个排序链表合并为一个新的排序链表 样例 给出 1->3->8->11->15->null,2->null, 返回 1->2->3- ...

  8. udp->ip & tcp->ip 发送数据包的目的地址的源地址是什么时候确定的?

    udp->ip & tcp->ip udp到ip层是:ip_send_skb tcp到ip层是: ip_queue_xmit 拿tcp为例,在使用[ip_queue_xmit, i ...

  9. AndroidStudio3.0 注解报错Annotation processors must be explicitly declared now. The following dependencies on the compile classpath are found to contain annotation processor.

    把Androidstudio2.2的项目放到3.0里面去了,然后开始报错了. 体验最新版AndroidStudio3.0 Canary 8的时候,发现之前项目的butter knife报错,用到注解的 ...

  10. InstallShield Limited Edition for Visual Studio 国内注册时国家无下拉框解决方法

    注册地址:http://learn.flexerasoftware.com/content/IS-EVAL-InstallShield-Limited-Edition-Visual-Studio 火狐 ...