[POJ3237]树的维护

P1424 - [POJ3237]树的维护

Description

给你由N个结点组成的树。树的节点被编号为1到N,边被编号为1到N-1。每一条边有一个权值。然后你要在树上执行一系列指令。指令可以是如下三种之一:

CHANGE i v:将第i条边的权值改成v。

NEGATE a b:将点a到点b路径上所有边的权值变成其相反数。

QUERY a b:找出点a到点b路径上各边的最大权值。

Input

第一行有一个整数N(N<=10000)。

接下来N-1行每行有三个整数a,b,c,代表点a和点b之间有一条权值为c的边。这些边按照其编号从小到大给出。

接下来是若干条指令(不超过10^5条),都按照上面所说的格式。

最后一行是"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

pre.cjk { font-family: "Droid Sans Fallback", monospace }
p { margin-bottom: 0.25cm; line-height: 120% }
a:link { }

树链剖分,在线段树中维护一个区间最大和区间最小,在进行取反操作时,将区间最小的相反数赋给最大,将区间最大值的相反数赋给最小,并标记lazy数组。
另外,根节点在线段树中的值为0,但这不需要管,因为不会查询到根节点。
  1 #include<set>
  2 #include<map>
  3 #include<queue>
  4 #include<stack>
  5 #include<ctime>
  6 #include<cmath>
  7 #include<string>
  8 #include<vector>
  9 #include<cstdio>
 10 #include<cstdlib>
 11 #include<cstring>
 12 #include<iostream>
 13 #include<algorithm>
 14 #define maxn 10010
 15 #define ls o*2
 16 #define rs o*2+1
 17 #define mi int mid=(l+r)>>1
 18 using namespace std;
 19 struct data{
 20   int nex,to,w;
 21 }e[maxn*2];
 22 char s[10];
 23 int head[maxn],edge=0,n;
 24 int top[maxn],dis[maxn],dad[maxn],son[maxn],size[maxn],dfn[maxn],dfp[maxn],deep[maxn];
 25 int b[maxn*4],b1[maxn*4],lazy[maxn*4];
 26 void dfs1(int x,int fa){
 27   size[x]++;
 28   for(int i=head[x];i;i=e[i].nex){
 29     int u=e[i].to;
 30     if(u==fa) continue;
 31     dad[u]=x;
 32     dis[u]=e[i].w;
 33     deep[u]=deep[x]+1;
 34     dfs1(u,x);
 35     size[x]+=size[u];
 36     if(size[u]>size[son[x]]) son[x]=u;
 37   }
 38 }
 39 int de=0;
 40 void dfs2(int x,int fa){
 41   ++de;
 42   dfn[x]=de;dfp[de]=x;
 43   if(son[x]!=0) top[son[x]]=top[x],dfs2(son[x],x);
 44   for(int i=head[x];i;i=e[i].nex){
 45     int v=e[i].to;
 46     if(v==fa || v==son[x]) continue;
 47     top[v]=v;
 48     dfs2(v,x);
 49   }
 50 }
 51 void add(int from,int to,int w){
 52   e[++edge].nex=head[from];
 53   e[edge].to=to;
 54   e[edge].w=w;
 55   head[from]=edge;
 56 }
 57 void build(int o,int l,int r){
 58   if(l==r){b[o]=dis[dfp[l]];b1[o]=dis[dfp[l]];return;}
 59   mi;
 60   build(ls,l,mid);build(rs,mid+1,r);
 61   b[o]=min(b[ls],b[rs]);
 62   b1[o]=max(b1[ls],b1[rs]);
 63 }
 64 void down(int o){
 65   if(lazy[o]==-1){
 66     int tmp=b[ls];
 67     b[ls]=-b1[ls];b1[ls]=-tmp;
 68   }
 69   if(lazy[o]==-1){
 70     int tmp=b[rs];
 71     b[rs]=-b1[rs];b1[rs]=-tmp;
 72   }
 73   lazy[ls]*=lazy[o],lazy[rs]*=lazy[o];
 74   lazy[o]=1;
 75 }
 76 int query(int o,int l,int r,int u,int v){
 77   if(l!=r)down(o);
 78   if(l>=u && r<=v) return b1[o];
 79   if(l>v || r<u) return -1999999999;
 80   mi;
 81   if(v<=mid) return query(ls,l,mid,u,v);
 82   else if(u>mid) return query(rs,mid+1,r,u,v);
 83   else return max(query(ls,l,mid,u,mid),query(rs,mid+1,r,mid+1,v));
 84 }
 85 int lca(int x,int y){
 86   int ans=-1999999999;
 87   while(top[x]!=top[y]){
 88     if(deep[top[x]]>deep[top[y]]) ans=max(ans,query(1,1,n,dfn[top[x]],dfn[x])),x=dad[top[x]];
 89     else ans=max(ans,query(1,1,n,dfn[top[y]],dfn[y])),y=dad[top[y]];
 90   }
 91   if(deep[x]>deep[y]) swap(x,y);
 92   if(x!=y)
 93     ans=max(ans,query(1,1,n,dfn[x]+1,dfn[y]));
 94   return ans;
 95 }
 96 void negatee(int o,int l,int r,int u,int v){
 97   if(l!=r)down(o);
 98   if(l>=u && r<=v){
 99     int tmp=b[o];
100     b[o]=-b1[o];b1[o]=-tmp;
101     lazy[o]*=-1;
102     return;
103   }
104   mi;
105   if(v<=mid) negatee(ls,l,mid,u,v);
106   else if(u>mid) negatee(rs,mid+1,r,u,v);
107   else negatee(ls,l,mid,u,mid),negatee(rs,mid+1,r,mid+1,v);
108   b[o]=min(b[ls],b[rs]);
109   b1[o]=max(b1[ls],b1[rs]);
110 }
111 void lca1(int x,int y){
112   while(top[x]!=top[y]){
113     if(deep[top[x]]>deep[top[y]]) negatee(1,1,n,dfn[top[x]],dfn[x]),x=dad[top[x]];
114     else negatee(1,1,n,dfn[top[y]],dfn[y]),y=dad[top[y]];
115   }
116   if(deep[x]>deep[y]) swap(x,y);
117   if(x!=y)
118     negatee(1,1,n,dfn[x]+1,dfn[y]);
119 }
120 void change(int o,int l,int r,int k,int p){
121   if(l!=r) down(o);
122   if(l==r){b[o]=p,b1[o]=p;return;}
123   mi;
124   if(k<=mid)change(ls,l,mid,k,p);
125   else change(rs,mid+1,r,k,p);
126   b[o]=min(b[ls],b[rs]);
127   b1[o]=max(b1[ls],b1[rs]);
128 }
129 int main()
130 {
131   freopen("!.in","r",stdin);
132   freopen("!.out","w",stdout);
133   scanf("%d",&n);int x,y,z;
134   for(int i=1;i<=4*n;i++) lazy[i]=1;
135   for(int i=1;i<n;i++)
136     scanf("%d%d%d",&x,&y,&z),add(x,y,z),add(y,x,z);
137   top[1]=1,dad[1]=1;
138   dfs1(1,0);dfs2(1,0);build(1,1,n);
139   while(1){
140     scanf("%s",s);
141     if(s[0]==‘D‘) break;
142     if(s[0]==‘Q‘){
143       int x,y;
144       scanf("%d%d",&x,&y);
145       printf("%d\n",lca(x,y));
146     }
147     if(s[0]==‘C‘){
148       int x,y;scanf("%d%d",&x,&y);
149       int k1=e[2*x-1].to,k2=e[2*x].to;
150       int k;
151       if(deep[k1]>deep[k2]) k=k1;
152       else k=k2;
153       change(1,1,n,dfn[k],y);
154     }
155     if(s[0]==‘N‘){
156       int x,y;
157       scanf("%d%d",&x,&y);
158       lca1(x,y);
159     }
160   }
161   return 0;
162 }

 
时间: 2024-10-15 09:21:56

[POJ3237]树的维护的相关文章

cogs1583. [POJ3237]树的维护

1583. [POJ3237]树的维护 http://www.cogs.pro/cogs/problem/problem.php?pid=1583 ★★★☆   输入文件:maintaintree.in   输出文件:maintaintree.out   简单对比时间限制:5 s   内存限制:128 MB [题目描述] 给你由N个结点组成的树.树的节点被编号为1到N,边被编号为1到N-1.每一条边有一个权值.然后你要在树上执行一系列指令.指令可以是如下三种之一: CHANGE i v:将第i条

COGS 1583. [POJ3237]树的维护

二次联通门 : COGS 1583. [POJ3237]树的维护 /* COGS 1583. [POJ3237]树的维护 树链剖分 + 边权化点权 线段树 单点修改 + 区间取相反数 + 查询区间最大 对于区间取相反数 考虑在线段树中维护两个值 一个区间最大, 一个区间最小 对于更改, 只需把区间最大与最小分别取相反数后交换即可 然后对于标记, 由于对区间连续取反两次相当于不变 则只需开一个bool 标记, 每次放标记时对标记取反即可 */ #include <cstdio> #define

线段树可维护的基本信息

一.区间最值 1.单点替换: 1 const int M=100001; 2 LL a[M]; 3 LL MAX[M<<2]; 4 #define lson l,m,rt<<1 5 #define rson m+1,r,rt<<1|1 6 void update(int rt){ 7 MAX[rt]=max(MAX[rt<<1],MAX[rt<<1|1]); 8 } 9 void build(int l,int r,int rt){ 10 if

线段树 --- (区间维护+逆推)

Buy Tickets Time Limit:4000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u Description Railway tickets were difficult to buy around the Lunar New Year in China, so we must get up early and join a long queue- The Lunar New Year was appro

hdu 1556 Color the ball(线段树区间维护+单点求值)

传送门:Color the ball Color the ball Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 25511    Accepted Submission(s): 12393 Problem Description N个气球排成一排,从左到右依次编号为1,2,3....N.每次给定2个整数a b(a <= b),lele

cogs 1583. [POJ 3237] 树的维护 树链剖分套线段树

1583. [POJ 3237] 树的维护 ★★★★   输入文件:maintaintree.in   输出文件:maintaintree.out   简单对比时间限制:5 s   内存限制:128 MB [题目描述] 给你由N个结点组成的树.树的节点被编号为1到N,边被编号为1到N-1.每一条边有一个权值.然后你要在树上执行一系列指令.指令可以是如下三种之一: CHANGE i v:将第i条边的权值改成v. NEGATE a b:将点a到点b路径上所有边的权值变成其相反数. QUERY a b

【BZOJ2653】middle,主席树(非权值线段树)维护区间01信息+二分答案

传送门 写在前面:虽然这是一道我再也不想写的题目,但很好很有价值 思路: cxlove大神: 要求中位数最大,首先二分中位数,然后判断可行不可行. 判断X可行不可行,对于区间内的数,凡是>=X的标为1,否则为-1.这样的话,求一次最大区间和 如果大于等于0,则说明可行. 这要求我们不能像之前那样建立权值线段树的主席树(区间即为权值)了,而是以权值为下标,维护区间[1,n]的信息,可能有点拗口,这里就理解是我们平常写的普通线段树好了,只是这里是n棵由于根的不同而信息不同的线段树 具体实现 对于题目

BZOJ 3779 重组病毒 LCT+线段树(维护DFS序)

原题干(由于是权限题我就直接砸出原题干了,要看题意概述的话在下面): Description 黑客们通过对已有的病毒反编译,将许多不同的病毒重组,并重新编译出了新型的重组病毒.这种病毒的繁殖和变异能力极强.为了阻止这种病毒传播,某安全机构策划了一次实验,来研究这种病毒.实验在一个封闭的局域网内进行.局域网内有n台计算机,编号为1~n.一些计算机之间通过网线直接相连,形成树形的结构.局域网中有一台特殊的计算机,称之为核心计算机.根据一些初步的研究,研究员们拟定了一个一共m步的实验.实验开始之前,核

CodeForces 587 E.Duff as a Queen 线段树动态维护区间线性基

https://codeforces.com/contest/587/problem/E 一个序列, 1区间异或操作 2查询区间子集异或种类数 题解 解题思路大同小异,都是利用异或的性质进行转化,std和很多网友用的都是差分的思想,用两棵线段树 第一棵维护差分序列上的线性基,第二棵维护原序列的异或区间和,两者同时进行修改 考虑两个序列 $(a,b)(d,e)$,按照std的想法,应该是维护$(0 \^ a,a \^ b)(0 \^ d,d \^ e)$ 然后合并首尾变成$(0 \^ a,a \^