题解

给你一棵基环树,环长为奇数(两点间最短路径只有一条)

维护两点间路径最大子段和,支持把一条路径上的值取反

显然只要断开一条边维护树上的值,然后对于那条边分类讨论就好了

维护树上的值可以通过树链剖分,然后对于左右附加一个值和区间跑最大子段和

把变量名打错了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!的更多相关文章

  1. 【CodeChef】Prime Distance On Tree

    vjudge 给定一棵边长都是\(1\)的树,求有多少条路径长度为质数 树上路径自然是点分治去搞,但是发现要求是长度为质数,总不能对每一个质数都判断一遍吧 自然是不行的,这个东西显然是一个卷积,我们合 ...

  2. 【BZOJ2959】长跑(Link-Cut Tree,并查集)

    [BZOJ2959]长跑(Link-Cut Tree,并查集) 题面 BZOJ 题解 如果保证不出现环的话 妥妥的\(LCT\)傻逼题 现在可能会出现环 环有什么影响? 那就可以沿着环把所有点全部走一 ...

  3. 【BZOJ2588】Count On a Tree(主席树)

    [BZOJ2588]Count On a Tree(主席树) 题面 题目描述 给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第 ...

  4. 【BZOJ2816】【ZJOI2012】网络(Link-Cut Tree)

    [BZOJ2816][ZJOI2012]网络(Link-Cut Tree) 题面 题目描述 有一个无向图G,每个点有个权值,每条边有一个颜色.这个无向图满足以下两个条件: 对于任意节点连出去的边中,相 ...

  5. 【CodeChef】Querying on a Grid(分治,最短路)

    [CodeChef]Querying on a Grid(分治,最短路) 题面 Vjudge CodeChef 题解 考虑分治处理这个问题,每次取一个\(mid\),对于\(mid\)上的三个点构建最 ...

  6. 【CF434E】Furukawa Nagisa's Tree 点分治

    [CF434E]Furukawa Nagisa's Tree 题意:一棵n个点的树,点有点权.定义$G(a,b)$表示:我们将树上从a走到b经过的点都拿出来,设这些点的点权分别为$z_0,z_1... ...

  7. 【CF725G】Messages on a Tree 树链剖分+线段树

    [CF725G]Messages on a Tree 题意:给你一棵n+1个节点的树,0号节点是树根,在编号为1到n的节点上各有一只跳蚤,0号节点是跳蚤国王.现在一些跳蚤要给跳蚤国王发信息.具体的信息 ...

  8. 【SPOJ】QTREE7(Link-Cut Tree)

    [SPOJ]QTREE7(Link-Cut Tree) 题面 洛谷 Vjudge 题解 和QTREE6的本质是一样的:维护同色联通块 那么,QTREE6同理,对于两种颜色分别维护一棵\(LCT\) 每 ...

  9. 【SPOJ】Count On A Tree II(树上莫队)

    [SPOJ]Count On A Tree II(树上莫队) 题面 洛谷 Vjudge 洛谷上有翻译啦 题解 如果不在树上就是一个很裸很裸的莫队 现在在树上,就是一个很裸很裸的树上莫队啦. #incl ...

  10. 【CodeChef】Palindromeness(回文树)

    [CodeChef]Palindromeness(回文树) 题面 Vjudge CodeChef 中文版题面 题解 构建回文树,现在的问题就是要求出当前回文串节点的长度的一半的那个回文串所代表的节点 ...

随机推荐

  1. 如何整合Office Web Apps至自己开发的系统(一)

    在前面我的一篇博客中 Office Web Apps安装部署(一),有一张介绍Office Web Apps与其他系统的关系图,   从上述图中,可知实际上Office Web Apps也是可以接入自 ...

  2. USACO Section 1.4 Mother's Milk 解题报告

    题目 题目描述 有三个牛奶桶,三个桶的容积分别是A,B,C,最小为1,最大为20.刚开始只有第三个桶里面装满了牛奶,其余两个桶都是空的.我们现在可以将第三个桶中的牛奶往其他两个桶里面倒一些牛奶,然后还 ...

  3. 【POJ2728】Desert King 最优比率生成树

    题目大意:给定一个 N 个点的无向完全图,边有两个不同性质的边权,求该无向图的一棵最优比例生成树,使得性质为 A 的边权和比性质为 B 的边权和最小. 题解:要求的答案可以看成是 0-1 分数规划问题 ...

  4. 2:jquery.cookie用法详细解析

    一个轻量级的cookie 插件,可以读取.写入.删除 cookie. jquery.cookie.js 的配置 首先包含jQuery的库文件,在后面包含 jquery.cookie.js 的库文件. ...

  5. cygwin简介及使用

    一个是真实的假货,一个是冒牌的真品前指 Cygwin,后指 Linux/VMWare 路不管平还是陡,终归你要走的,如果你愿意投入到linux开发的社群中来,不会安装linux系统,不会配置工作环境是 ...

  6. 弹指之间 -- Waltz

    CHAPTER 18 华尔兹 Waltz 示例歌曲:白桦林,丁香花

  7. map文件的使用

    map文件相信大家并不陌生,大家都知道是用来调试的,但是具体怎么用你又清不清楚呢? 其实也很简单 1.拿JQ为例,我们需要备有jquery.js.jquery.min.js.jquery.min.ma ...

  8. git安装与初始化

    命令行 Git有多重方式使用 原生命令行,才能使用git所有命令,会git命令再去用gui图形工具,完全无压力 GUI图形软件,只是实现了git的部分功能,以减免操作难度,难以记住git原生命令 不同 ...

  9. Crypto 模块安装

    crypto模块的目的是为了提供通用的加密和哈希算法. AES是一种常用的对称加密算法,加解密都用同一个密钥.crypto模块提供了AES支持,但是需要自己封装好函数,便于使用 方法一: 1,到 ht ...

  10. HDU 2056 龟兔赛跑 (DP)

    题意:见题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2059 解题报告:以前一直没看出来这题是个DP题,知道是DP题就简单了 .首先要把起点和终点看成 ...