树链剖分-链的剖分(线段树维护边权值的更新)
来源:互联网 发布:3d合值九宫计算法 编辑:程序博客网 时间:2024/06/07 11:50
poj3237
Description
You are given a tree with N nodes. The tree’s nodes are numbered 1 through N and its edges are numbered 1 through N − 1. Each edge is associated with a weight. Then you are to execute a series of instructions on the tree. The instructions can be one of the following forms:
CHANGE
i vChange the weight of the ith edge to vNEGATE
a bNegate the weight of every edge on the path from a to bQUERY
a bFind the maximum weight of edges on the path from a to bInput
The input contains multiple test cases. The first line of input contains an integer t (t ≤ 20), the number of test cases. Then follow the test cases.
Each test case is preceded by an empty line. The first nonempty line of its contains N (N ≤ 10,000). The next N − 1 lines each contains three integers a, b and c, describing an edge connecting nodes a and bwith weight c. The edges are numbered in the order they appear in the input. Below them are the instructions, each sticking to the specification above. A lines with the word “DONE
” ends the test case.
Output
For each “QUERY
” instruction, output the result on a separate line.
Sample Input
131 2 12 3 2QUERY 1 2CHANGE 1 3QUERY 1 2DONE
Sample Output
13
题意:给出一颗树以及边权值,对边权有三种操作:(1)把第i条边的权值改成v;(2)把<u,v>路径上的边权值改为原来的相反数;(3)输出<u,v>路径上的最大权值;
程序:
#include"stdio.h"#include"string.h"#include"iostream"#include"map"#include"string"#include"queue"#include"stdlib.h"#include"math.h"#define M 11009#define eps 1e-10#define inf 1000000000#define mod 1000000000#define INF 1000000000using namespace std;struct node{ int u,v,w,next;}edge[M*2];int t,head[M];int son[M];//记录重链中某点的儿子节点,子叶节点的儿子为-1;int fa[M];//记录每个节点的父节点;int num[M];//记录以该节点为根的子树中有多少个节点;int top[M];//记录某条重链中所有节点的最初节点编号;int p[M];//记录某个节点的编号(对原来的节点重新编号)int fp[M];//记录某编号的节点对应的原来的节点编号;int deep[M];//记录某个节点在树中的深度;int a[M];//记录编过号的节点与其父节点之间的边的边权值;维护的线段树是n-1个点int pos;int Max;void init(){ t=pos=0; memset(head,-1,sizeof(head)); memset(son,-1,sizeof(son));}void add(int u,int v){ edge[t].u=u; edge[t].v=v; edge[t].next=head[u]; head[u]=t++;}void dfs(int u,int f,int d){ deep[u]=d; num[u]=1; fa[u]=f; for(int i=head[u];i!=-1;i=edge[i].next) { int v=edge[i].v; if(v!=f) { dfs(v,u,d+1); num[u]+=num[v]; if(son[u]==-1||num[son[u]]<num[v]) son[u]=v; } }}void getpos(int u,int sp){ top[u]=sp; p[u]=pos++; fp[p[u]]=u; if(son[u]==-1)return; getpos(son[u],sp); for(int i=head[u];i!=-1;i=edge[i].next) { int v=edge[i].v; if(v!=fa[u]&&v!=son[u]) getpos(v,v); }}//以上是求重链//***************************以下是线段树操作****************************//struct Node{ int l,r,flag,maxi,mini;}tree[M*4];void pushup(int i){ tree[i].maxi=max(tree[i*2].maxi,tree[i*2+1].maxi); tree[i].mini=min(tree[i*2].mini,tree[i*2+1].mini);}void pushdown(int i)//lazy操作{ if(tree[i].l==tree[i].r)return; if(tree[i].flag) { tree[i*2].maxi=-tree[i*2].maxi; tree[i*2].mini=-tree[i*2].mini; swap(tree[i*2].maxi,tree[i*2].mini); tree[i*2].flag^=1; tree[i*2+1].maxi=-tree[i*2+1].maxi; tree[i*2+1].mini=-tree[i*2+1].mini; swap(tree[i*2+1].maxi,tree[i*2+1].mini); tree[i*2+1].flag^=1; tree[i].flag=0; }}void make(int l,int r,int i)//建立线段树{ tree[i].l=l; tree[i].r=r; tree[i].flag=0; if(tree[i].l==tree[i].r) { tree[i].maxi=tree[i].mini=a[tree[i].l]; return; } int mid=(l+r)>>1; make(l,mid,i*2); make(mid+1,r,i*2+1); pushup(i);}void change(int p,int q,int i)//单点更新{ if(tree[i].l==p&&tree[i].r==p) { tree[i].maxi=tree[i].mini=q; tree[i].flag=0; return; } pushdown(i); int mid=(tree[i].l+tree[i].r)>>1; if(p<=mid)change(p,q,i*2); else change(p,q,i*2+1); pushup(i);}void negval(int l,int r,int i)//区间修改为相反数{ if(tree[i].l==l&&tree[i].r==r) { tree[i].maxi=-tree[i].maxi; tree[i].mini=-tree[i].mini; swap(tree[i].maxi,tree[i].mini); tree[i].flag^=1; return; } pushdown(i); int mid=(tree[i].l+tree[i].r)>>1; if(r<=mid) negval(l,r,i*2); else if(l>mid) negval(l,r,i*2+1); else { negval(l,mid,i*2); negval(mid+1,r,i*2+1); } pushup(i);}void query(int l,int r,int i)//区间查找{ if(tree[i].l==l&&tree[i].r==r) { Max=max(Max,tree[i].maxi); return; } pushdown(i); int mid=(tree[i].l+tree[i].r)>>1; if(r<=mid) query(l,r,i*2); else if(l>mid) query(l,r,i*2+1); else { query(l,mid,i*2); query(mid+1,r,i*2+1); } pushup(i);}int findmax(int u,int v)//树形图转换为线段树结构,并查找最大值{ int f1=top[u]; int f2=top[v]; int ans=-inf; while(f1!=f2) { if(deep[f1]<deep[f2]) { swap(f1,f2); swap(u,v); } Max=-inf; query(p[f1],p[u],1); ans=max(ans,Max); u=fa[f1]; f1=top[u]; } if(v==u)return ans; if(deep[u]>deep[v])swap(u,v); Max=-inf; query(p[son[u]],p[v],1); ans=max(ans,Max); return ans;}void neg(int u,int v)//树形图转换为线段树结构,并修改区间值{ int f1=top[u]; int f2=top[v]; while(f1!=f2) { if(deep[f1]<deep[f2]) { swap(f1,f2); swap(u,v); } negval(p[f1],p[u],1); u=fa[f1]; f1=top[u]; } if(v==u)return; if(deep[u]>deep[v])swap(u,v); negval(p[son[u]],p[v],1); return;}struct Edge{ int u,v,w;}e[M];int main(){ int T,i,n; cin>>T; while(T--) { scanf("%d",&n); init(); for(i=1;i<n;i++) { scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w); add(e[i].u,e[i].v); add(e[i].v,e[i].u); } dfs(1,1,0); getpos(1,1); for(i=1;i<n;i++) { if(deep[e[i].u]<deep[e[i].v]) swap(e[i].v,e[i].u); a[p[e[i].u]]=e[i].w; } make(1,pos-1,1); char ch[22]; int x,y; while(scanf("%s",ch),strcmp(ch,"DONE")!=0) { scanf("%d%d",&x,&y); if(ch[0]=='Q') { printf("%d\n",findmax(x,y)); } else if(ch[0]=='C') { change(p[e[x].u],y,1); } else neg(x,y); } } return 0;}
- 树链剖分-链的剖分(线段树维护边权值的更新)
- 树链剖分-链的剖分(线段树维护+离线操作)
- 树链剖分 SPOJ375 线段树的维护
- 线段树维护区间的和和单点更新-HDU1166-敌兵布阵
- BZOJ 1798-维护序列seq(线段树区间更新)
- 用线段树维护树的直径
- Codeforces Round 718C(维护矩阵的线段树)
- 斐波纳契数列 线段树的维护
- poj 3468 线段树区间更新维护
- poj3237(树链剖分边维护+线段树区间更新)
- EC2的维护更新
- (Relax 线段树1.1)POJ 3468 A Simple Problem with Integers(线段树子区间更新的维护:集中更新和动态统计子序列中的数据)
- 【整合】树链剖分模板(线段树维护)
- 线段树的模板(更新ing)
- 线段树的区间更新
- 线段树的区间更新
- 51nod 1766 线段树维护树的直径
- HDU 4288 Coder 线段树维护区间%5的和
- 模拟解hdu1283 最简单的计算机
- TCP/IP SOCKET HTTP及HTTPS之间的关系及各自特性之总结
- Opencascade学习
- MTK面试归来
- HDOJ 题目1084 钱币兑换问题(母函数,打表)
- 树链剖分-链的剖分(线段树维护边权值的更新)
- Android App 隐藏标题栏+状态栏+导航栏
- Win7 64位下配置Qt5.3和Wincap
- 每日小结
- IOS成长中 C语言之函数
- 题目1185:特殊排序
- Deep Learning学习过程
- JNI for android projection
- poj 2349 Arctic Network 最小生成树