BSOJ1125:树Tree 树链剖分 单点修改 区间取反 区间查询
来源:互联网 发布:数值模拟软件 编辑:程序博客网 时间:2024/04/30 02:16
1125 -- 【POJ3237】树Tree
Description
给你一颗具有n个结点的树,结点编号为1到n且边的编号为1到n-1。每条边有一个边权。现要求模拟下列三种操作:
1.CHANGE i v:修改第i条边的权值为v
2.NEGATE a b:把a点到b点之间路径的边权全部取反;
3.QUERY a b:询问a点到b点之间路径的最大边权;
Input
第一行为一个整数N(N<=30000);
接下来N-1行,每行包含三个整数a,b,c,表示a到b有一条边,边权为c。边的编号是按照输入的顺序。接下来是若干个询问,以一行一个单词“DONE”作为这组数据的结束。
Output
对于每个“QUERY”输出一行。
Sample Input
3
1 2 1
2 3 2
QUERY 1 2
CHANGE 1 3
QUERY 1 2
DONE
Sample Output
1
3
这道题涉及三个问题 1.单边(点)修改 2.区间取反 3.区间最大
区间最大,就是在Pushup维护的时候从儿子得到最大,输入时直接赋值就好了。
重点是第二问,区间取反。
其实也没什么特别的,跟区间修改类似,一个递归+一个爬top[]就可以解决,记录lazy标记,下传给儿子。
*但是取反之后,区间max怎么维护?
一开始想的顺其自然,*=-1,上传维护,耶耶耶。
哦嚯,这样的想法是错误的。
权值取相反数之后,原maxx变为最小,原minn变为最大。
于是我们要维护一个minn来维护maxx.
取反,minn和maxx*=-1,交换,即可维护maxx了,happy ending.
贴上代码,错误&易错注释在下
这道题涉及三个问题 1.单边(点)修改 2.区间取反 3.区间最大
区间最大,就是在Pushup维护的时候从儿子得到最大,输入时直接赋值就好了。
重点是第二问,区间取反。
其实也没什么特别的,跟区间修改类似,一个递归+一个爬top[]就可以解决,记录lazy标记,下传给儿子。
*但是取反之后,区间max怎么维护?
一开始想的顺其自然,*=-1,上传维护,耶耶耶。
哦嚯,这样的想法是错误的。
权值取相反数之后,原maxx变为最小,原minn变为最大。
于是我们要维护一个minn来维护maxx.
取反,minn和maxx*=-1,交换,即可维护maxx了,happy ending.
贴上代码,错误&易错注释在下
#include<iostream>#include<cstdio>#include<cstring>#define L(x) (x<<1)#define R(x) (x<<1|1)#define INF 0x7fffffffusing namespace std;int fa[300005]={0},top[300005]={0},son[300005]={0},size[300005]={0};int tid[300005]={0},dep[300005]={0};struct SegmentTree{int l,r,minn,maxx,neg;}tree[300005];struct TREE{int x,y,v;}t[300005]={0};struct Edge{int to,next;}w[300005]={0};int tim=0;int cnt=0;int Max=-INF;int h[300005]={0};void add(int x,int y){cnt++;w[cnt].to=y;w[cnt].next=h[x];h[x]=cnt;}void DFS1(int x,int f,int d){dep[x]=d;fa[x]=f;size[x]=1;for(int i=h[x];i;i=w[i].next){int to=w[i].to;if(to!=f){DFS1(to,x,d+1);size[x]+=size[to];if(son[x]==0||size[son[x]]<size[to])son[x]=to;}}}void DFS2(int x,int tp){top[x]=tp;tid[x]=++tim;if(son[x]==0)return;DFS2(son[x],tp);for(int i=h[x];i;i=w[i].next){int to=w[i].to;if(to!=son[x]&&to!=fa[x])DFS2(to,to);}}void Pushup(int x){tree[x].maxx=max(tree[L(x)].maxx,tree[R(x)].maxx);tree[x].minn=min(tree[L(x)].minn,tree[R(x)].minn);return;}void Pushdown(int x){if(tree[x].neg)//取反懒惰标记下传,改变儿子以及他们的懒惰标记{int l=L(x),r=R(x);tree[l].neg^=1;tree[r].neg^=1;tree[l].maxx*=-1;tree[l].minn*=-1;swap(tree[l].maxx,tree[l].minn);tree[r].maxx*=-1;tree[r].minn*=-1;swap(tree[r].maxx,tree[r].minn);tree[x].neg=0;//注意清零}return;}void build(int l,int r,int root){tree[root].l=l;tree[root].r=r;tree[root].maxx=0;tree[root].minn=0;tree[root].neg=0;if(l==r)return;int mid=(l+r)>>1;build(l,mid,L(root));build(mid+1,r,R(root));Pushup(root);}//递归首部下传底部上传,安全正确有保险。void change(int x,int data,int root){Pushdown(root);if(tree[root].l==x&&tree[root].r==x){tree[root].maxx=data;tree[root].minn=data;return;}int mid=(tree[root].l+tree[root].r)>>1;if(x<=mid)change(x,data,L(root));else change(x,data,R(root));Pushup(root);}void DoNeg(int l,int r,int root){Pushdown(root);if(l<=tree[root].l&&tree[root].r<=r){tree[root].neg=1;//一开始忘了标记懒惰了!血崩!tree[root].maxx*=-1;tree[root].minn*=-1;swap(tree[root].maxx,tree[root].minn);return;}int mid=(tree[root].l+tree[root].r)>>1;if(l<=mid)DoNeg(l,r,L(root));if(r>mid)DoNeg(l,r,R(root));Pushup(root);}void GetNeg(int x,int y){int t1=top[x],t2=top[y];while(t1!=t2){if(dep[t1]<dep[t2]){swap(t1,t2);swap(x,y);}DoNeg(tid[t1],tid[x],1);//分清楚什么时候用tid映射!x=fa[t1];t1=top[x];}if(x==y)return;if(dep[x]>dep[y])swap(x,y);DoNeg(tid[son[x]],tid[y],1);}void getmax(int l,int r,int root){Pushdown(root);if(l<=tree[root].l&&tree[root].r<=r){Max=max(Max,tree[root].maxx);return;}int mid=(tree[root].l+tree[root].r)>>1;if(l<=mid)getmax(l,r,L(root));if(r>mid)getmax(l,r,R(root));Pushup(root);}void MAX(int x,int y){int t1=top[x],t2=top[y];while(t1!=t2){if(dep[t1]<dep[t2]){swap(t1,t2);swap(x,y);}getmax(tid[t1],tid[x],1); x=fa[t1];t1=top[x];}if(dep[x]>dep[y])swap(x,y);getmax(tid[son[x]],tid[y],1);}int n;void init(){scanf("%d",&n);for(int i=1;i<n;i++){scanf("%d%d%d",&t[i].x,&t[i].y,&t[i].v);add(t[i].x,t[i].y);add(t[i].y,t[i].x);}DFS1(1,0,1);DFS2(1,1);build(1,n,1);for(int i=1;i<n;i++){if(dep[t[i].x]>dep[t[i].y])swap(t[i].x,t[i].y);change(tid[t[i].y],t[i].v,1);}}void solve(){int a,b,c,d;char cmd[10];while(1){scanf("%s",&cmd);if(cmd[0]=='D')break;if(cmd[0]=='Q'){Max=-INF;//注意还原scanf("%d%d",&a,&b);MAX(a,b);printf("%d\n",Max);}if(cmd[0]=='C'){scanf("%d%d",&a,&b);change(tid[t[a].y],b,1);}if(cmd[0]=='N'){scanf("%d%d",&a,&b);GetNeg(a,b);}}}int main(){init();solve();return 0;}
0 0
- BSOJ1125:树Tree 树链剖分 单点修改 区间取反 区间查询
- POJ 3237 Tree(树链剖分 + 单点更新 + 区间更新 + 区间查询)
- 【数据结构】【线段树】单点修改区间查询
- 线段树(单点修改,区间查询)
- 线段树(区间修改,单点查询)
- HDU1166 线段树 单点修改、区间查询
- 树状数组(单点修改区间查询、区间修改单点查询、区间修改区间查询)
- 树状数组-单点修改区间查询-区间修改单点查询-区间修改区间查询
- hdu1166 单点修改区间查询
- 【树状数组】【单点修改区间求和】【区间修改单点查询】【单点修改区间最大值查询】
- POJ 3321 Apple Tree(DFS序+线段树单点修改区间查询)
- BSOJ2783:Housewife Wind 树链剖分 单点修改 区间查询
- BSOJ1120:树上的询问 树链剖分 区间修改 单点查询
- Wikilo 1191线段树区间修改单点查询
- POJ 2155 Matrix 二维线段树 区间修改 单点查询
- hdu 1754 线段树单点修改+区间查询
- hdu 4819 二维线段树,单点修改区间查询
- 考试 线段树二分+单点修改+区间查询
- leetcode - Maximum Product of Word Lengths
- BSOJ1120:树上的询问 树链剖分 区间修改 单点查询
- Android的各种布局
- webmin的安装
- hdu(1686)——Oulipo
- BSOJ1125:树Tree 树链剖分 单点修改 区间取反 区间查询
- BSOJ3194:黑白树 树链剖分 TLE90分
- 记一次手贱之旅--Ubuntu安装NVIDIA驱动
- LeetCode 136.137. 260.Single Number ⅠII III
- BSOJ2381:捉迷藏 括号序列 线段树维护
- 【点分治】poj1741
- Android基础:startActivityForResult+onActivityResult+setResult
- 【点分治】poj1741
- 阿里2015实习生招聘前端方向--编程题(2)