BZOJ2157 边转点 树链剖分
https://www.lydsy.com/JudgeOnline/problem.php?id=2157
现在就是后悔,非常后悔
本来想随便拿个树剖热身,不料开了个毒瘤题。
题意:动态维护一棵树上的链最大值,最小值,和,修改的操作是一条链全部取反以及一条边单点修改
边转点是肯定要边转点的,把所有的边化成两端深度更深的那个点的权值,然后直接上树剖化成线段树
线段树就是很常规的最大小值还有和,单点修改就直接改,区间修改就打lazy标记,对于一个区间的取反操作,和直接取反,最大小值互换之后取反。
问题在于对树链u,v操作的时候,lca(u,v)这个点是不可以算进去的,因为边转点的特性这个点不属于这条树链,所以考虑对u到lca和v到lca这两条树链分别操作,这样lca这个点就是需要查询(修改)的序列的端点,在操作的时候手动 + 1把这个点忽略掉就可以。
整体感觉不难,唯一的毒瘤点在于写起来很麻烦
#include <map>
#include <set>
#include <ctime>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
#define For(i, x, y) for(int i=x;i<=y;i++)
#define _For(i, x, y) for(int i=x;i>=y;i--)
#define Mem(f, x) memset(f,x,sizeof(f))
#define Sca(x) scanf("%d", &x)
#define Sca2(x,y) scanf("%d%d",&x,&y)
#define Sca3(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define Scl(x) scanf("%lld",&x);
#define Pri(x) printf("%d\n", x)
#define Prl(x) printf("%lld\n",x);
#define CLR(u) for(int i=0;i<=N;i++)u[i].clear();
#define LL long long
#define ULL unsigned long long
#define mp make_pair
#define PII pair<int,int>
#define PIL pair<int,long long>
#define PLL pair<long long,long long>
#define pb push_back
#define fi first
#define se second
typedef vector<int> VI;
int read(){int x = ,f = ;char c = getchar();while (c<'' || c>''){if (c == '-') f = -;c = getchar();}
while (c >= ''&&c <= ''){x = x * + c - '';c = getchar();}return x*f;}
const double eps = 1e-;
const int maxn = ;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + ;
int N,M,K;
struct Edge{
int to,next,dis,id;
}edge[maxn * ];
int head[maxn],tot;
void init(){
for(int i = ; i <= N + ; i ++) head[i] = -;
tot = ;
}
void add(int u,int v,int w,int id){
edge[tot].to = v;
edge[tot].id = id;
edge[tot].next = head[u];
edge[tot].dis = w;
head[u] = tot++;
}
int nw[maxn];
int Index[maxn];
int dep[maxn],top[maxn],fa[maxn],val[maxn];
int pos[maxn],size[maxn],son[maxn];
const int SP = ;
int pa[maxn][SP];
void dfs1(int t,int la){
size[t] = ; son[t] = t;
pa[t][] = la;
for(int i = ; i < SP; i ++) pa[t][i] = pa[pa[t][i - ]][i - ];
int heavy = ;
for(int i = head[t]; ~i ; i = edge[i].next){
int v = edge[i].to;
if(v == la) continue;
dep[v] = dep[t] + ;
fa[v] = t; val[v] = edge[i].dis;
Index[edge[i].id] = v;
dfs1(v,t);
if(size[v] > heavy){
heavy = size[v];
son[t] = v;
}
size[t] += size[v];
}
}
int lca(int u,int v){
if(dep[u] < dep[v]) swap(u,v);
int t = dep[u] - dep[v];
for(int i = ; i < SP; i ++){
if(t & ( << i)) u = pa[u][i];
}
for(int i = SP - ; i >= ; i --){
int uu = pa[u][i],vv = pa[v][i];
if(uu != vv){
u = uu;
v = vv;
}
}
return u == v?u : pa[u][];
}
int cnt;
void dfs2(int t,int la){
top[t] = la;
pos[t] = ++cnt;
nw[cnt] = val[t];
if(son[t] == t) return;
dfs2(son[t],la);
for(int i = head[t]; ~i ; i = edge[i].next){
int v = edge[i].to;
if((fa[t] == v) || (v == son[t])) continue;
dfs2(v,v);
}
}
struct Tree{
int l,r;
int Min,Sum,Max;
int lazy;
}tree[maxn << ];
void Pushup(int t){
tree[t].Min = min(tree[t << ].Min,tree[t << | ].Min);
tree[t].Max = max(tree[t << ].Max,tree[t << | ].Max);
tree[t].Sum = tree[t << ].Sum + tree[t << | ].Sum;
}
void Build(int t,int l,int r){
tree[t].l = l; tree[t].r = r;
tree[t].lazy = ;
if(l == r){
tree[t].Min = tree[t].Sum = tree[t].Max = nw[l];
return;
}
int m = (l + r) >> ;
Build(t << ,l,m); Build(t << | ,m + ,r);
Pushup(t);
}
void change(int t){
tree[t].Sum = -tree[t].Sum;
swap(tree[t].Max,tree[t].Min);
tree[t].Max = -tree[t].Max;
tree[t].Min = -tree[t].Min;
tree[t].lazy ^= ;
}
void Pushdown(int t){
if(tree[t].lazy){
change(t << );
change(t << | );
tree[t].lazy = ;
}
}
void update1(int t,int p,int x){
if(tree[t].l == tree[t].r){
tree[t].Sum = tree[t].Max = tree[t].Min = x;
return;
}
Pushdown(t);
int m = (tree[t].l + tree[t].r) >> ;
if(p <= m) update1(t << ,p,x);
else update1(t << | ,p,x);
Pushup(t);
}
void update2(int t,int l,int r){
if(l <= tree[t].l && tree[t].r <= r){
change(t);
return;
}
Pushdown(t);
int m = (tree[t].l + tree[t].r) >> ;
if(r <= m) update2(t << ,l,r);
else if(l > m) update2(t << | ,l,r);
else{
update2(t << ,l,m);
update2(t << | ,m + ,r);
}
Pushup(t);
}
int query(int t,int l,int r,int p){
if(l <= tree[t].l && tree[t].r <= r){
if(p == ) return tree[t].Sum;
else if(p == ) return tree[t].Max;
return tree[t].Min;
}
Pushdown(t);
int m = (tree[t].l + tree[t].r) >> ;
if(r <= m) return query(t << ,l,r,p);
else if(l > m) return query(t << | ,l,r,p);
else{
if(p == ) return query(t << ,l,m,p) + query(t << | ,m + ,r,p);
else if(p == ) return max(query(t << ,l,m,p),query(t << | ,m + ,r,p));
else return min(query(t << ,l,m,p),query(t << | ,m + ,r,p));
}
}
void update(int u,int v){
while(top[u] != top[v]){
update2(,pos[top[u]],pos[u]);
u = fa[top[u]];
}
if(u != v) update2(,pos[v] + ,pos[u]);
}
int query(int u,int v,int p){
int ans = ;
if(p == ) ans = -INF;
else if(p == ) ans = INF;
while(top[u] != top[v]){
int t = query(,pos[top[u]],pos[u],p);
if(p == ) ans += t;
else if(p == ) ans = max(ans,t);
else ans = min(ans,t);
u = fa[top[u]];
}
if(u != v){
int t = query(,pos[v] + ,pos[u],p);
if(p == ) ans += t;
else if(p == ) ans = max(ans,t);
else ans = min(ans,t);
}
return ans;
}
int main(){
Sca(N); init();
for(int i = ; i <= N - ; i ++){
int u,v,w; Sca3(u,v,w);
u++;v++;
add(u,v,w,i); add(v,u,w,i);
}
int root = ; dfs1(root,);
cnt = ;
dfs2(root,root);
Build(,,N);
Sca(M);
while(M--){
char op[]; int u,v;
scanf("%s%d%d",op,&u,&v);
u++;v++; int l;
if(op[] == 'C') v--,u--;
else l = lca(u,v);
if(op[] == 'C'){
update1(,pos[Index[u]],v);
}else if(op[] == 'N'){
update(u,l); update(v,l);
}else if(op[] == 'S'){
Pri(query(u,l,) + query(v,l,));
}else if(op[] == 'A'){
Pri(max(query(u,l,),query(v,l,)));
}else{
Pri(min(query(u,l,),query(v,l,)));
}
}
return ;
}
BZOJ2157 边转点 树链剖分的更多相关文章
- 【BZOJ2157】旅游(树链剖分,Link-Cut Tree)
[BZOJ2157]旅游(树链剖分,Link-Cut Tree) 题面 Description Ray 乐忠于旅游,这次他来到了T 城.T 城是一个水上城市,一共有 N 个景点,有些景点之间会用一座桥 ...
- ⌈洛谷1505⌋⌈BZOJ2157⌋⌈国家集训队⌋旅游【树链剖分】
题目链接 [洛谷] [BZOJ] 题目描述 Ray 乐忠于旅游,这次他来到了T 城.T 城是一个水上城市,一共有 N 个景点,有些景点之间会用一座桥连接.为了方便游客到达每个景点但又为了节约成本,T ...
- BZOJ2157旅游——树链剖分+线段树
题目描述 Ray 乐忠于旅游,这次他来到了T 城.T 城是一个水上城市,一共有 N 个景点,有些景点之间会用一座桥连接.为了方便游客到达每个景点但又为了节约成本,T 城的任意两个景点之间有且只有一条路 ...
- BZOJ2157: 旅游 树链剖分 线段树
http://www.lydsy.com/JudgeOnline/problem.php?id=2157 在对树中数据进行改动的时候需要很多pushdown(具体操作见代码),不然会wa,大概原因 ...
- BZOJ 3626: [LNOI2014]LCA [树链剖分 离线|主席树]
3626: [LNOI2014]LCA Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 2050 Solved: 817[Submit][Status ...
- BZOJ 1984: 月下“毛景树” [树链剖分 边权]
1984: 月下“毛景树” Time Limit: 20 Sec Memory Limit: 64 MBSubmit: 1728 Solved: 531[Submit][Status][Discu ...
- codevs 1228 苹果树 树链剖分讲解
题目:codevs 1228 苹果树 链接:http://codevs.cn/problem/1228/ 看了这么多树链剖分的解释,几个小时后总算把树链剖分弄懂了. 树链剖分的功能:快速修改,查询树上 ...
- 并查集+树链剖分+线段树 HDOJ 5458 Stability(稳定性)
题目链接 题意: 有n个点m条边的无向图,有环还有重边,a到b的稳定性的定义是有多少条边,单独删去会使a和b不连通.有两种操作: 1. 删去a到b的一条边 2. 询问a到b的稳定性 思路: 首先删边考 ...
- 树链剖分+线段树 CF 593D Happy Tree Party(快乐树聚会)
题目链接 题意: 有n个点的一棵树,两种操作: 1. a到b的路径上,给一个y,对于路径上每一条边,进行操作,问最后的y: 2. 修改某个条边p的值为c 思路: 链上操作的问题,想树链剖分和LCT,对 ...
随机推荐
- hdu-4300(kmp或者拓展kmp)
题意:乱七八糟说了一大堆,就是先给你一个长度26的字符串,对应了abcd....xyz,这是一个密码表.然后给你一个字符串,这个字符串是不完整的(完整的应该是前半部分是加密的,后半部分是解密了的),然 ...
- Android Spinner 绑定键值对
这里给大家提供下绑定 spinner键值对的方法. 首先创建绑定模型BaseItem public class BaseItem { public BaseItem(Integer id,String ...
- 51Nod1778 小Q的集合 【组合数】【Lucas定理】
题目分析: 题解好高深...... 我给一个辣鸡做法算了,题解真的看不懂. 注意到方差恒为$0$,那么其实就是要我们求$\sum_{i=0}^{n}\binom{n}{i}(i^k-(n-i)^k)^ ...
- Codeforces986E Prince's Problem 【虚树】【可持久化线段树】【树状数组】
我很喜欢这道题. 题目大意: 给出一棵带点权树.对每个询问$ u,v,x $,求$\prod_{i \in P(u,v)}gcd(ai,x)$.其中$ P(u,v) $表示$ u $到$ v $的路径 ...
- 【BZOJ4033】【HAOI2015】树上染色 树形DP
题目描述 给你一棵\(n\)个点的树,你要把其中\(k\)个点染成黑色,剩下\(n-k\)个点染成白色.要求黑点两两之间的距离加上白点两两之间距离的和最大.问你最大的和是多少. \(n\leq 200 ...
- 【XSY1544】fixed 数学 强连通图计数
题目描述 给你一个\(n\times n\)的方阵\(A\).定义方阵\(A\)的不动点\((i,j)\)为:\(\forall p,q\geq 0,(A^p)_{i,j}=(A^q)_{i,j} ...
- bzoj 2429: [HAOI2006]聪明的猴子 (最小生成树)
链接:https://www.lydsy.com/JudgeOnline/problem.php?id=2429 思路:就是找最小生成树最大的一条边,最小生成树的性质,最后加入的那条边就是最大的 实现 ...
- 【AtCoder078D】Fennec VS. Snuke
AtCoder Regular Contest 078 D - Fennec VS. Snuke 题意 给一个树,1是白色,n是黑色,其它没有颜色.Fennec每次可以染白色点的直接邻居为白色.Snu ...
- 【luogu3733】【HAOI2017】 八纵八横 (线段树分治+线性基)
Descroption 原题链接 给你一个\(n\)个点的图,有重边有自环保证连通,最开始有\(m\)条固定的边,要求你支持加边删边改边(均不涉及最初的\(m\)条边),每一次操作都求出图中经过\(1 ...
- 【Luogu3602】Koishi Loves Segments(贪心)
[Luogu3602]Koishi Loves Segments(贪心) 题面 洛谷 题解 离散区间之后把所有的线段挂在左端点上,从左往右扫一遍. 对于当前点的限制如果不满足显然会删掉右端点最靠右的那 ...