【CodeChef】QTREE- Queries on tree again!
题解
给你一棵基环树,环长为奇数(两点间最短路径只有一条)
维护两点间路径最大子段和,支持把一条路径上的值取反
显然只要断开一条边维护树上的值,然后对于那条边分类讨论就好了
维护树上的值可以通过树链剖分,然后对于左右附加一个值和区间跑最大子段和
把变量名打错了orz,死亡
代码
#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define pdi pair<db,int>
#define mp make_pair
#define pb push_back
#define enter putchar('\n')
#define space putchar(' ')
#define eps 1e-8
#define mo 974711
#define MAXN 100005
//#define ivorysi
using namespace std;
typedef long long int64;
typedef double db;
template<class T>
void read(T &res) {
res = 0;char c = getchar();T f = 1;
while(c < '0' || c > '9') {
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9') {
res = res * 10 + c - '0';
c = getchar();
}
res *= f;
}
template<class T>
void out(T x) {
if(x < 0) {x = -x;putchar('-');}
if(x >= 10) {
out(x / 10);
}
putchar('0' + x % 10);
}
int N,M;
struct node {
int to,next;int64 val;
}E[MAXN * 2];
int head[MAXN],sumE;
int fa[MAXN],dfn[MAXN],siz[MAXN],dep[MAXN],idx,son[MAXN],top[MAXN],seq[MAXN];
int md[MAXN * 2][20],len[MAXN * 2],pos[MAXN],bud;
int st,ed;int64 ev;
int64 worth[MAXN];
bool vis[MAXN];
void add(int u,int v,int64 c) {
E[++sumE].to = v;
E[sumE].next = head[u];
E[sumE].val = c;
head[u] = sumE;
}
int min_dep(int a,int b) {
return dep[a] < dep[b] ? a : b;
}
int lca(int a,int b) {
a = pos[a];b = pos[b];
if(a > b) swap(a,b);
int l = len[b - a + 1];
return min_dep(md[a][l],md[b - (1 << l) + 1][l]);
}
int dis(int a,int b) {
return dep[a] + dep[b] - 2 * dep[lca(a,b)] + 1;
}
void dfs1(int u) {
dep[u] = dep[fa[u]] + 1;
vis[u] = 1;
pos[u] = ++bud;md[bud][0] = u;
siz[u] = 1;
for(int i = head[u] ; i ; i = E[i].next) {
int v = E[i].to;
if(!vis[v]) {
fa[v] = u;
dfs1(v);
md[++bud][0] = u;
worth[v] = E[i].val;
siz[u] += siz[v];
if(siz[v] > siz[son[u]]) son[u] = v;
}
else if(dep[v] < dep[u] && v != fa[u]) {
st = u;ed = v;ev = E[i].val;
}
}
}
void dfs2(int u) {
vis[u] = 1;
dfn[u] = ++idx;
seq[idx] = u;
if(!top[u]) top[u] = u;
if(son[u]) {
top[son[u]] = top[u];
dfs2(son[u]);
}
for(int i = head[u] ; i ; i = E[i].next) {
int v = E[i].to;
if(!vis[v] && !(u == st && v == ed) && !(u == ed && v == st)) dfs2(v);
}
}
namespace seg_tr {
struct node {
int L,R;
int64 lmax,lmin,rmax,rmin,sum,val,mval;
bool resign;
}tr[MAXN * 4];
#define lc(u) u << 1
#define rc(u) u << 1 | 1
#define sum(u) tr[u].sum
#define lmin(u) tr[u].lmin
#define rmin(u) tr[u].rmin
#define lmax(u) tr[u].lmax
#define rmax(u) tr[u].rmax
#define val(u) tr[u].val
#define mval(u) tr[u].mval
void resign(int u) {
sum(u) = -sum(u);
lmin(u) = -lmin(u);lmax(u) = -lmax(u);
swap(lmin(u),lmax(u));
rmin(u) = -rmin(u);rmax(u) = -rmax(u);
swap(rmin(u),rmax(u));
val(u) = -val(u);mval(u) = -mval(u);
swap(val(u),mval(u));
tr[u].resign ^= 1;
}
void push_down(int u) {
if(tr[u].resign) {
resign(lc(u));resign(rc(u));
tr[u].resign = 0;
}
}
void update(int u) {
sum(u) = sum(lc(u)) + sum(rc(u));
lmax(u) = max(lmax(lc(u)),sum(lc(u)) + lmax(rc(u)));
lmin(u) = min(lmin(lc(u)),sum(lc(u)) + lmin(rc(u)));
rmax(u) = max(rmax(rc(u)),rmax(lc(u)) + sum(rc(u)));
rmin(u) = min(rmin(rc(u)),rmin(lc(u)) + sum(rc(u)));
val(u) = max(val(lc(u)),val(rc(u)));
val(u) = max(val(u),rmax(lc(u)) + lmax(rc(u)));
mval(u) = min(mval(lc(u)),mval(rc(u)));
mval(u) = min(mval(u),rmin(lc(u)) + lmin(rc(u)));
}
void build(int u,int l,int r) {
tr[u].L = l;tr[u].R = r;
if(l == r) {
lmax(u) = rmax(u) = val(u) = max(0LL,worth[seq[l]]);
lmin(u) = rmin(u) = mval(u) = min(0LL,worth[seq[l]]);
sum(u) = worth[seq[l]];
return;
}
int mid = (l + r) >> 1;
build(u << 1,l,mid);
build(u << 1 | 1,mid + 1,r);
update(u);
}
int64 query_val(int u,int l,int r,int64 &v,bool on) {
if(tr[u].L == l && tr[u].R == r) {
int64 res = val(u);
if(on) res = max(res,v + rmax(u));
else res = max(res,v + lmax(u));
if(on) v = max(v + sum(u),lmax(u));
else v = max(v + sum(u),rmax(u));
return res;
}
push_down(u);
int mid = (tr[u].L + tr[u].R) >> 1;
if(r <= mid) return query_val(lc(u),l,r,v,on);
else if(l > mid) return query_val(rc(u),l,r,v,on);
else {
if(!on) {
int t = query_val(lc(u),l,mid,v,on);
int h = query_val(rc(u),mid + 1,r,v,on);
return max(t,h);
}
else {
int t = query_val(rc(u),mid + 1,r,v,on);
int h = query_val(lc(u),l,mid,v,on);
return max(t,h);
}
}
}
pair<int64,int64> query_max(int u,int l,int r,bool on) {
if(tr[u].L == l && tr[u].R == r) {
if(!on) return mp(lmax(u),sum(u));
else return mp(rmax(u),sum(u));
}
push_down(u);
int mid = (tr[u].L + tr[u].R) >> 1;
if(r <= mid) return query_max(lc(u),l,r,on);
else if(l > mid) return query_max(rc(u),l,r,on);
else {
pair<int64,int64> t,h;
t = query_max(lc(u),l,mid,on);
h = query_max(rc(u),mid + 1,r,on);
if(!on) {
return mp(max(t.fi,h.fi + t.se),t.se + h.se);
}
else {
return mp(max(h.fi,t.fi + h.se),t.se + h.se);
}
}
}
void change(int u,int l,int r) {
if(tr[u].L == l && tr[u].R == r) {
resign(u);return;
}
push_down(u);
int mid = (tr[u].L + tr[u].R) >> 1;
if(r <= mid) change(lc(u),l,r);
else if(l > mid) change(rc(u),l,r);
else {
change(lc(u),l,mid);change(rc(u),mid + 1,r);
}
update(u);
}
int64 Query_max(int l,int r,int64 v,bool on) {
pair<int64,int64> t = query_max(1,l,r,on);
return max(t.fi,v + t.se);
}
void Change(int l,int r) {
change(1,l,r);
}
int64 Query_val(int l,int r,int64 v,bool on) {
return query_val(1,l,r,v,on);
}
}
void Init() {
read(N);
int u,v;int64 c;
for(int i = 1 ; i <= N ; ++i) {
read(u);read(v);read(c);
add(u,v,c);add(v,u,c);
}
dfs1(1);
memset(vis,0,sizeof(vis));
dfs2(1);
seg_tr::build(1,1,N);
for(int j = 1 ; j <= 18 ; ++j) {
for(int i = 1 ; i <= bud ; ++i) {
if(i + (1 << j) - 1 > bud) break;
md[i][j] = min_dep(md[i][j - 1],md[i + (1 << j - 1)][j - 1]);
}
}
for(int i = 2 ; i <= bud ; ++i) len[i] = len[i / 2] + 1;
}
void Change_Path(int u,int v) {
while(top[u] != top[v]) {
if(dfn[top[u]] < dfn[top[v]]) swap(u,v);
seg_tr::Change(dfn[top[u]],dfn[u]);
u = fa[top[u]];
}
if(dep[u] > dep[v]) swap(u,v);
if(u != v) seg_tr::Change(dfn[u] + 1,dfn[v]);
}
vector<pii> b;
pair<int64,int64> Query_Path(int u,int v,int64 pre) {
int f = lca(u,v);
int64 ans = pre;
b.clear();
while(top[u] != top[f]) {
ans = max(ans,seg_tr::Query_val(dfn[top[u]],dfn[u],pre,1));
pre = seg_tr::Query_max(dfn[top[u]],dfn[u],pre,0);
u = fa[top[u]];
}
if(f != u) {
ans = max(ans,seg_tr::Query_val(dfn[f] + 1,dfn[u],pre,1));
pre = seg_tr::Query_max(dfn[f] + 1,dfn[u],pre,0);
}
while(top[v] != top[f]) {
b.pb(mp(top[v],v));
v = fa[top[v]];
}
if(f != v) {
b.pb(mp(seq[dfn[f] + 1],v));
}
for(int i = b.size() - 1 ; i >= 0 ; --i) {
ans = max(ans,seg_tr::Query_val(dfn[b[i].fi],dfn[b[i].se],pre,0));
pre = seg_tr::Query_max(dfn[b[i].fi],dfn[b[i].se],pre,1);
}
return mp(ans,pre);
}
void Pf(int u,int v) {
if(dis(u,st) + dis(ed,v) > dis(u,v)) Change_Path(u,v);
else {Change_Path(u,st);Change_Path(ed,v);ev = -ev;}
}
int64 P(int u,int v) {
if(dis(u,st) + dis(ed,v) > dis(u,v)) return Query_Path(u,v,0).fi;
else {
pair<int64,int64> t = Query_Path(u,st,0);
t.se = max(0LL,t.se + ev);
t.fi = max(t.fi,Query_Path(ed,v,t.se).fi);
return t.fi;
}
}
void Solve() {
read(M);
char op[5];
int u,v;
for(int i = 1 ; i <= M ; ++i) {
scanf("%s",op + 1);read(u);read(v);
if(dis(st,u) + dis(ed,v) > dis(st,v) + dis(ed,u)) swap(u,v);
if(op[1] == 'f') Pf(u,v);
else {out(P(u,v));enter;}
}
}
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
Init();
Solve();
return 0;
}
【CodeChef】QTREE- Queries on tree again!的更多相关文章
- 【CodeChef】Prime Distance On Tree
vjudge 给定一棵边长都是\(1\)的树,求有多少条路径长度为质数 树上路径自然是点分治去搞,但是发现要求是长度为质数,总不能对每一个质数都判断一遍吧 自然是不行的,这个东西显然是一个卷积,我们合 ...
- 【BZOJ2959】长跑(Link-Cut Tree,并查集)
[BZOJ2959]长跑(Link-Cut Tree,并查集) 题面 BZOJ 题解 如果保证不出现环的话 妥妥的\(LCT\)傻逼题 现在可能会出现环 环有什么影响? 那就可以沿着环把所有点全部走一 ...
- 【BZOJ2588】Count On a Tree(主席树)
[BZOJ2588]Count On a Tree(主席树) 题面 题目描述 给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第 ...
- 【BZOJ2816】【ZJOI2012】网络(Link-Cut Tree)
[BZOJ2816][ZJOI2012]网络(Link-Cut Tree) 题面 题目描述 有一个无向图G,每个点有个权值,每条边有一个颜色.这个无向图满足以下两个条件: 对于任意节点连出去的边中,相 ...
- 【CodeChef】Querying on a Grid(分治,最短路)
[CodeChef]Querying on a Grid(分治,最短路) 题面 Vjudge CodeChef 题解 考虑分治处理这个问题,每次取一个\(mid\),对于\(mid\)上的三个点构建最 ...
- 【CF434E】Furukawa Nagisa's Tree 点分治
[CF434E]Furukawa Nagisa's Tree 题意:一棵n个点的树,点有点权.定义$G(a,b)$表示:我们将树上从a走到b经过的点都拿出来,设这些点的点权分别为$z_0,z_1... ...
- 【CF725G】Messages on a Tree 树链剖分+线段树
[CF725G]Messages on a Tree 题意:给你一棵n+1个节点的树,0号节点是树根,在编号为1到n的节点上各有一只跳蚤,0号节点是跳蚤国王.现在一些跳蚤要给跳蚤国王发信息.具体的信息 ...
- 【SPOJ】QTREE7(Link-Cut Tree)
[SPOJ]QTREE7(Link-Cut Tree) 题面 洛谷 Vjudge 题解 和QTREE6的本质是一样的:维护同色联通块 那么,QTREE6同理,对于两种颜色分别维护一棵\(LCT\) 每 ...
- 【SPOJ】Count On A Tree II(树上莫队)
[SPOJ]Count On A Tree II(树上莫队) 题面 洛谷 Vjudge 洛谷上有翻译啦 题解 如果不在树上就是一个很裸很裸的莫队 现在在树上,就是一个很裸很裸的树上莫队啦. #incl ...
- 【CodeChef】Palindromeness(回文树)
[CodeChef]Palindromeness(回文树) 题面 Vjudge CodeChef 中文版题面 题解 构建回文树,现在的问题就是要求出当前回文串节点的长度的一半的那个回文串所代表的节点 ...
随机推荐
- MT【190】绝对值的和
(2012浙江压轴题)已知$a>0,b\in R$,函数$f(x)=4ax^3-2bx-a+b$.1)证明:当$0\le x\le 1$时,i)函数$f(x)$的最大值为$|2a-b|+a;$i ...
- 【刷题】LOJ 6121 「网络流 24 题」孤岛营救问题
题目描述 1944 年,特种兵麦克接到国防部的命令,要求立即赶赴太平洋上的一个孤岛,营救被敌军俘虏的大兵瑞恩.瑞恩被关押在一个迷宫里,迷宫地形复杂,但幸好麦克得到了迷宫的地形图.迷宫的外形是一个长方形 ...
- 【CF771A】Bear and Friendship Condition
题目大意:给定一张无向图,要求如果 A 与 B 之间有边,B 与 C 之间有边,那么 A 与 C 之间也需要有边.问这张图是否满足要求. 题解:根据以上性质,即:A 与 B 有关系,B 与 C 有关系 ...
- 查找和替换img src
$("#imgId")[0].src; //获取 $("#imgId").attr('src',path); //修改
- webpack:代码分割与按需加载
代码分割就是我们根据实际业务需求将代码进行分割,然后在合适的时候在将其加载进入文档中. 代码中总有些东西我们希望拆分开来,比如: 使用概率较低的模块,希望后期使用的时候异步加载 框架代码,希望能利用浏 ...
- Nginx配置项优化(转载)
(1)nginx运行工作进程个数,一般设置cpu的核心或者核心数x2 如果不了解cpu的核数,可以top命令之后按1看出来,也可以查看/proc/cpuinfo文件 grep ^processor / ...
- [转载]五理由 .NET开发者应该关注HTML 5
http://developer.51cto.com/art/201107/275039.htm
- bash脚本:集群资源争夺战crazy-killer
背景 公司的集群很多人一起用,有时候就难免资源紧张,某次需要用的时候没资源等了半天还是没资源,再等半天还是没资源,于是就写了个脚本泄愤,建议看到的人拷走放在自己公司集群上长期运行 :) 实现 此脚本运 ...
- 面积并+扫描线 覆盖的面积 HDU - 1255
题目链接:https://cn.vjudge.net/problem/HDU-1255 题目大意:中文题目 具体思路:和上一篇的博客思路差不多,上一个题求的是面积,然后我们这个地方求的是啊覆盖两次及两 ...
- Python 入门基础9 --函数基础2 实参与形参
今日内容: 一.函数参数 1.形参与实参定义 2.实参分类 3.形参分类 4.可变参数的整体使用 一.形参与实参定义 def fn(参数们): pass 1.1 形参 定义函数,在括号内声明的变量名, ...