COJ 1006 树上操作

传送门:http://oj.cnuschool.org.cn/oj/home/problem.htm?problemID=979

WZJ的数据结构(六)
难度级别:D; 运行时间限制:1000ms; 运行空间限制:51200KB; 代码长度限制:2000000B

试题描述

给你一棵N个节点的无根树,边之间有权值。请你设计一个数据结构,进行以下两种操作:

1.修改:给你a、b,将第a条边的权值改为b。

2.询问:给你a、b,输出从a到b路径上的最大值、最小值与权值和,如果a=b,输出"error"。


输入

第一行为一个正整数N。
接下来N-1行为每一条边,每行3个正整数a,b,c,表示有一条从a到b权值为c的边(从1开始编号)。
第N+1行为一个正整数Q,表示Q次操作。
接下来Q行为每一次询问,每行3个正整数t,a,b,若t=1表示询问,t=0表示修改。

输出

对于每一次询问,输出三个正整数,即最大值、最小值与权值和,如果a=b,输出"error"。

输入示例


1 2 4
1 4 5
3 4 6
2 5 7
4
1 1 5
1 2 5
0 1 2
1 1 5

输出示例

7 4 11
7 7 7
7 2 9

其他说明

1<=N,Q<=50000
1<=c<=1000
询问中的1<=a,b<=N
修改中的1<=a<=N-1,1<=b<=1000

题解:懒得写树链剖分了LCT走起

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cmath>
  4 #include<algorithm>
  5 #include<queue>
  6 #include<cstring>
  7 #define PAU putchar(‘ ‘)
  8 #define ENT putchar(‘\n‘)
  9 using namespace std;
 10 const int maxn=100000+10,inf=-1u>>1;
 11 inline int read(){
 12     int x=0,sig=1;char ch=getchar();
 13     while(!isdigit(ch)){if(ch==‘-‘)sig=-1;ch=getchar();}
 14     while(isdigit(ch))x=10*x+ch-‘0‘,ch=getchar();
 15     return x*=sig;
 16 }
 17 inline void write(int x){
 18     if(x==0){putchar(‘0‘);return;}if(x<0)putchar(‘-‘),x=-x;
 19     int len=0,buf[15];while(x)buf[len++]=x%10,x/=10;
 20     for(int i=len-1;i>=0;i--)putchar(buf[i]+‘0‘);return;
 21 }
 22 struct node {
 23     int x,mi,mx,sm,set;bool rev;
 24     node *ch[2],*fa;
 25     inline void add_rev_tag(){
 26         swap(ch[0],ch[1]);rev^=1;return;
 27     }
 28     inline void add_set_tag(int a){
 29         x=set=a;
 30         if(mi!=inf) mi=set;
 31         if(mx!=-inf) mx=set;
 32     }
 33     inline void down(){
 34         if(rev){
 35             if(ch[0]) ch[0]->add_rev_tag();
 36             if(ch[1]) ch[1]->add_rev_tag();
 37             rev=0;
 38         }
 39         if(set){
 40             if(ch[0]) ch[0]->add_set_tag(set);
 41             if(ch[1]) ch[1]->add_set_tag(set);
 42             set=0;
 43         }
 44         return;
 45     }
 46     inline void update(){
 47         sm=x;mi=inf;mx=-inf;
 48         if(ch[0]) sm+=ch[0]->sm,mi=min(mi,ch[0]->mi),mx=max(mx,ch[0]->mx);
 49         if(ch[1]) sm+=ch[1]->sm,mi=min(mi,ch[1]->mi),mx=max(mx,ch[1]->mx);
 50         if(!x) return;
 51         mi=min(x,mi);
 52         mx=max(x,mx);
 53         return;
 54     }
 55 }lct[maxn];
 56 inline int get_parent(node *x,node *&fa){return (fa=x->fa)?fa->ch[0]==x?0:fa->ch[1]==x?1:-1:-1;}
 57 inline void rotate(node *x){
 58     int t1,t2;
 59     node *fa,*gfa;
 60     t1=get_parent(x,fa);
 61     t2=get_parent(fa,gfa);
 62     if ((fa->ch[t1]=x->ch[t1^1])) fa->ch[t1]->fa=fa;
 63     x->ch[t1^1]=fa;fa->fa=x;x->fa=gfa;
 64     if (t2!=-1) gfa->ch[t2]=x;
 65     fa->update();return;
 66 }
 67 inline void pushdown(node *x){
 68     static node *stack[maxn];
 69     int cnt=0;
 70     while(1){
 71         stack[cnt++]=x;
 72         node *fa=x->fa;
 73         if (!fa || (fa->ch[0]!=x && fa->ch[1]!=x)) break;
 74         x=fa;
 75     }
 76     while(cnt--) stack[cnt]->down();
 77     return;
 78 }
 79 inline node * splay(node *x){
 80     pushdown(x);
 81     while(1){
 82         int t1,t2;
 83         node *fa,*gfa;
 84         t1=get_parent(x,fa);
 85         if(t1==-1) break;
 86         t2=get_parent(fa,gfa);
 87         if(t2==-1){
 88             rotate(x);break;
 89         } else if (t1==t2){
 90             rotate(fa);rotate(x);
 91         } else{
 92             rotate(x);rotate(x);
 93         }
 94     }
 95     x->update();
 96     return x;
 97 }
 98 inline node * access(node *x){
 99     node *ret=NULL;
100     while (x) splay(x)->ch[1]=ret,(ret=x)->update(),x=x->fa;
101     return ret;
102 }
103 inline void makeroot(int x){access(lct+x)->add_rev_tag();}
104 inline void link(int u,int v){
105     makeroot(u);splay(lct+u)->fa=lct+v;return;
106 }
107 int n,q;
108 int main(){
109     n=read();
110     int i;
111     int lim=n<<1;
112     for(i=1;i<=lim;i++) {
113         lct[i]=(node){0,inf,-inf,0,0,0};
114     }
115     for(i=1;i<n;i++){
116         int u,v,w;
117         u=read();v=read();
118         link(u,i+n);link(v,i+n);lct[i+n].add_set_tag(read());
119     }
120     q=read();
121     int x,y,c;
122     while(q--){
123         c=read();x=read();y=read();
124         if(c==0) makeroot(x+n),access(x+n+lct)->add_set_tag(y);
125         else{
126             if(x==y){puts("error");continue;}
127             makeroot(x);node*t=access(y+lct);
128             write(t->mx);PAU;write(t->mi);PAU;write(t->sm);ENT;
129         }
130     }
131     return 0;
132 }

搜索

复制

时间: 2024-10-10 13:23:04

COJ 1006 树上操作的相关文章

【BZOJ4034】[HAOI2015]树上操作 树链剖分+线段树

[BZOJ4034][HAOI2015]树上操作 Description 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a . 操作 3 :询问某个节点 x 到根的路径中所有点的点权和. Input 第一行包含两个整数 N, M .表示点数和操作数. 接下来一行 N 个整数,表示树中节点的初始权值. 接下来 N-1 行每行三个正整数 fr, to

HAOI 树上操作

P1457 - [HAOI2015]树上操作 Description 有一棵点数为N的树,以点1为根,且树点有边权.然后有M个操作,分为三种: 操作1:把某个节点x的点权增加a. 操作2:把某个节点x为根的子树中所有点的点权都增加a. 操作3:询问某个节点x到根的路径中所有点的点权和. Input 第一行两个整数N,M,表示点数和操作数. 接下来一行N个整数,表示树中节点的初始权值. 接下来N-1行每行两个正整数fr,to,表示该树中存在一条边(fr,to). 再接下来M行,每行分别表示一次操作

[HAOI2015]树上操作

[HAOI2015]树上操作 2017-09-07 Description 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a . 操作 3 :询问某个节点 x 到根的路径中所有点的点权和. Input 第一行包含两个整数 N, M .表示点数和操作数.接下来一行 N 个整数,表示树中节点的初始权值.接下来 N-1 行每行三个正整数 fr, to ,

[HAOI2015]树上操作 -树链剖分

1963. [HAOI2015]树上操作 [题目描述] 有一棵点数为N的树,以点1为根,且树点有权值.然后有M个操作,分为三种: 操作1:把某个节点x的点权增加a. 操作2:把某个节点x为根的子树中所有点的点权都增加a. 操作3:询问某个节点x到根的路径中所有点的点权和. [输入格式] 第一行两个整数N,M,表示点数和操作数. 接下来一行N个整数,表示树中节点的初始权值. 接下来N-1行每行两个正整数fr,to,表示该树中存在一条边(fr,to). 再接下来M行,每行分别表示一次操作.其中第一个

bzoj 4034: [HAOI2015]树上操作 树链剖分+线段树

4034: [HAOI2015]树上操作 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 4352  Solved: 1387[Submit][Status][Discuss] Description 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a . 操作 3 :询问某个节点 x 到根的路径中所有

BZOJ 4034 HAOI2015 树上操作

4034: [HAOI2015]树上操作 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 6033  Solved: 1959[Submit][Status][Discuss] Description 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a . 操作 3 :询问某个节点 x 到根的路径中所有

bzoj千题计划242:bzoj4034: [HAOI2015]树上操作

http://www.lydsy.com/JudgeOnline/problem.php?id=4034 dfs序,树链剖分 #include<cstdio> #include<iostream> using namespace std; #define N 100001 typedef long long LL; int n,a[N]; int front[N],nxt[N<<1],to[N<<1],tot; int fa[N],siz[N],dep[N]

bzoj4034: [HAOI2015]树上操作(树剖)

4034: [HAOI2015]树上操作 题目:传送门 题解: 树剖裸题: 麻烦一点的就只有子树修改(其实一点也不),因为子树编号连续啊,直接改段(记录编号最小和最大) 开个long long 水模版 代码: 1 #include<cstdio> 2 #include<cstring> 3 #include<cstdlib> 4 #include<cmath> 5 #include<algorithm> 6 using namespace std

4034: [HAOI2015]树上操作

4034: [HAOI2015]树上操作 链接 思路: 树链剖分.操作:单点修改,路径查询,子树修改. 代码: 1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #include<iostream> 5 #include<cmath> 6 #include<cctype> 7 8 using namespace std; 9 10 const int N =