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.

贴上代码,错误&易错注释在下
#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
原创粉丝点击