luoguP2590 [ZJOI2008]树的统计 [树链剖分] [TLE的LCT]

题目描述

一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w。

我们将以下面的形式来要求你对这棵树完成一些操作:

I. CHANGE u t : 把结点u的权值改为t

II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值

III. QSUM u v: 询问从点u到点v的路径上的节点的权值和

注意:从点u到点v的路径上的节点包括u和v本身

输入输出格式

输入格式:

输入文件的第一行为一个整数n,表示节点的个数。

接下来n – 1行,每行2个整数a和b,表示节点a和节点b之间有一条边相连。

接下来一行n个整数,第i个整数wi表示节点i的权值。

接下来1行,为一个整数q,表示操作的总数。

接下来q行,每行一个操作,以“CHANGE u t”或者“QMAX u v”或者“QSUM u v”的形式给出。

输出格式:

对于每个“QMAX”或者“QSUM”的操作,每行输出一个整数表示要求输出的结果。

输入输出样例

输入样例#1:

4
1 2
2 3
4 1
4 2 1 3
12
QMAX 3 4
QMAX 3 3
QMAX 3 2
QMAX 2 3
QSUM 3 4
QSUM 2 1
CHANGE 1 5
QMAX 3 4
CHANGE 3 6
QMAX 3 4
QMAX 2 4
QSUM 3 4

输出样例#1:

4
1
2
2
10
6
5
6
5
16

说明

对于100%的数据,保证1<=n<=30000,0<=q<=200000;中途操作中保证每个节点的权值w在-30000到30000之间。



这题本身应该是一题树链剖分果题。。QAQ

  1 //不用lazy-tag真是爽!
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<iostream>
  5 using namespace std;
  6 #define inf 0x3f3f3f3f
  7 #define ls x<<1
  8 #define rs x<<1|1
  9
 10 int read(){
 11     char ch;
 12     int re=0;
 13     bool flag=0;
 14     while((ch=getchar())!=‘-‘&&(ch<‘0‘||ch>‘9‘));
 15     ch==‘-‘?flag=1:re=ch-‘0‘;
 16     while((ch=getchar())>=‘0‘&&ch<=‘9‘)  re=re*10+ch-‘0‘;
 17     return flag?-re:re;
 18 }
 19
 20 struct Edge{
 21     int to,nxt;
 22     Edge(int to=0,int nxt=0):
 23         to(to),nxt(nxt){}
 24 };
 25
 26 struct Segment{
 27     int l,r,su,mx;
 28     Segment(){
 29         mx=-inf;
 30     }
 31 };
 32
 33 const int maxn=30005;
 34
 35 int n,m,cnt=0,dc=1;
 36 int head[maxn],val[maxn];
 37 int top[maxn],dep[maxn],fa[maxn],id[maxn],son[maxn],sz[maxn];
 38 Edge G[maxn<<1];
 39 Segment T[maxn<<2];
 40
 41 inline void a_ed(int from,int to){
 42     G[++cnt]=Edge(to,head[from]),head[from]=cnt;
 43     G[++cnt]=Edge(from,head[to]),head[to]=cnt;
 44 }
 45
 46 inline void push_up(int x){
 47     T[x].mx=max(T[ls].mx,T[rs].mx);
 48     T[x].su=T[ls].su+T[rs].su;
 49 }
 50
 51 void build(int x,int l,int r){
 52     T[x].l=l,T[x].r=r;
 53     if(l==r){
 54         T[x].su=T[x].mx=val[l];
 55         return;
 56     }
 57     int mid=l+r>>1;
 58     build(ls,l,mid);  build(rs,mid+1,r);
 59     push_up(x);
 60 }
 61
 62 void update(int x,int M,int c){
 63     if(T[x].l==T[x].r){
 64         T[x].su=T[x].mx=c;
 65         return;
 66     }
 67     int mid=T[x].l+T[x].r>>1;
 68     if(M<=mid)  update(ls,M,c);
 69     else  update(rs,M,c);
 70     push_up(x);
 71 }
 72
 73 int query(int x,int L,int R,bool kind){
 74     if(L<=T[x].l&&T[x].r<=R)
 75         if(kind)  return T[x].su;
 76         else  return T[x].mx;
 77     int mid=T[x].l+T[x].r>>1;
 78     if(R<=mid)  return query(ls,L,R,kind);
 79     else  if(L>mid)  return query(rs,L,R,kind);
 80     else{
 81         if(kind)  return query(ls,L,mid,kind)+query(rs,mid+1,R,kind);
 82         else  return max(query(ls,L,mid,kind),query(rs,mid+1,R,kind));
 83     }
 84 }
 85
 86 void dfs1(int no,int p){
 87     fa[no]=p;
 88     sz[no]=1;
 89     dep[no]=dep[p]+1;
 90     for(int e=head[no];e;e=G[e].nxt){
 91         int nt=G[e].to;
 92         if(nt!=p){
 93             dfs1(nt,no);
 94             sz[no]+=sz[nt];
 95             if(!son[no]||sz[nt]>sz[son[no]])
 96                 son[no]=nt;
 97         }
 98     }
 99 }
100
101 void dfs2(int no,int p){
102     if(!son[no])  return;
103     top[son[no]]=top[no];
104     id[son[no]]=++dc;
105     dfs2(son[no],no);
106     for(int e=head[no];e;e=G[e].nxt){
107         int nt=G[e].to;
108         if(nt!=p&&nt!=son[no]){
109             top[nt]=nt;
110             id[nt]=++dc;
111             dfs2(nt,no);
112         }
113     }
114 }
115
116 int calc(int x,int y,bool kind){
117     int sum=0,f1=top[x],f2=top[y];
118     if(!kind)  sum=-inf;
119     while(f1!=f2){
120         if(dep[f1]<dep[f2]){  swap(f1,f2),swap(x,y);  }
121         if(kind)
122             sum+=query(1,id[f1],id[x],kind);
123         else
124             sum=max(sum,query(1,id[f1],id[x],kind));
125         x=fa[f1];
126         f1=top[x];
127     }
128     if(dep[x]>dep[y])  swap(x,y);
129     if(kind)  sum+=query(1,id[x],id[y],kind);
130     else  sum=max(sum,query(1,id[x],id[y],kind));
131     return sum;
132 }
133
134 int main(){
135 //    freopen("temp.in","r",stdin);
136     n=read();
137     for(int i=1,from,to;i<n;i++){
138         from=read();  to=read();
139         a_ed(from,to);
140     }
141     dfs1(1,0);
142     top[1]=1;
143     id[1]=1;
144     dfs2(1,0);
145     for(int i=1;i<=n;i++)  val[id[i]]=read();
146     build(1,1,n);
147     m=read();
148     char opt[10];
149     int x,y;
150     while(m--){
151         scanf("%s",opt);
152         x=read(),y=read();
153         switch(opt[1]){
154             case ‘H‘:{
155                 update(1,id[x],y);
156                 break;
157             }
158             case ‘M‘:{
159                 printf("%d\n",calc(x,y,0));
160                 break;
161             }
162             default:{
163                 printf("%d\n",calc(x,y,1));
164                 break;
165             }
166         }
167     }
168     return 0;
169 }

刚学了LCT的我。。想用LCT过了这一题。。

可是。。T了。。QAQ

顺便终于明白、、把一堆变量包进一个结构体里还不用指针构成的splay还不如拆成一个个数组。。

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<iostream>
  4 using namespace std;
  5 #define rint register int
  6 #define inf 0x3f3f3f3f
  7
  8 int read(){
  9     char ch;
 10     int re=0;
 11     bool flag=0;
 12     while((ch=getchar())!=‘-‘&&(ch<‘0‘||ch>‘9‘));
 13     ch==‘-‘?flag=1:re=ch-‘0‘;
 14     while((ch=getchar())>=‘0‘&&ch<=‘9‘)  re=re*10+ch-‘0‘;
 15     return flag?-re:re;
 16 }
 17
 18 struct Edge{
 19     int to,nxt;
 20     Edge(int to=0,int nxt=0):
 21         to(to),nxt(nxt){}
 22 };
 23
 24 const int maxn=30005;
 25
 26 int n,m,cnt=0,top;
 27 //struct 变 数组
 28 int ch[maxn][2],su[maxn],mx[maxn],fa[maxn],rev[maxn];
 29 int head[maxn],val[maxn],stk[maxn];
 30 Edge G[maxn<<1];
 31
 32 inline void a_ed(int from,int to){
 33     G[++cnt]=Edge(to,head[from]);
 34     head[from]=cnt;
 35     G[++cnt]=Edge(from,head[to]);
 36     head[to]=cnt;
 37 }
 38
 39 inline void push_up(int x){
 40     mx[x]=max(mx[ch[x][0]],max(mx[ch[x][1]],val[x]));
 41     su[x]=su[ch[x][0]]+su[ch[x][1]]+val[x];
 42 }
 43
 44 inline void push_down(int x){
 45     if(rev[x]){
 46         rev[ch[x][0]]^=1,rev[ch[x][1]]^=1;
 47         swap(ch[x][0],ch[x][1]);
 48         rev[x]=0;
 49     }
 50 }
 51
 52 inline bool isroot(int x){
 53     return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;
 54 }
 55
 56 void rot(int x){
 57     int y=fa[x],z=fa[y],l,r;
 58     fa[x]=z;
 59     if(!isroot(y))  ch[z][ch[z][1]==y]=x;
 60     if(ch[y][0]==x)  l=0;
 61     else  l=1;
 62     r=l^1;
 63     fa[ch[x][r]]=y;
 64     ch[y][l]=ch[x][r];
 65     fa[y]=x;
 66     ch[x][r]=y;
 67     push_up(y),push_up(x);
 68 }
 69
 70 void splay(int x){
 71     top=1;  stk[top]=x;
 72     for(rint i=x;!isroot(i);i=fa[i])  stk[++top]=fa[i];
 73     for(rint i=top;i;i--)  push_down(stk[i]);
 74     while(!isroot(x)){
 75         int y=fa[x],z=fa[y];
 76         if(!isroot(y)){
 77             if((ch[y][0]==x)^(ch[z][0]==y))  rot(x);
 78             else  rot(y);
 79         }
 80         rot(x);
 81     }
 82 }
 83
 84 void acc(int x){
 85     int t=0;
 86     while(x){
 87         splay(x);
 88         ch[x][1]=t;
 89         push_up(x);
 90         t=x;  x=fa[x];
 91     }
 92 }
 93
 94 void make_root(int x){  acc(x),splay(x),rev[x]^=1;  }
 95
 96 void split(int x,int y){  make_root(x),acc(y),splay(y);  }
 97
 98 void dfs(int no,int fat){
 99     fa[no]=fat;
100     for(rint e=head[no];e;e=G[e].nxt)
101         if(G[e].to!=fat)
102             dfs(G[e].to,no);
103 }
104
105 int main(){
106 //    freopen("temp.in","r",stdin);
107     n=read();
108     for(rint i=1,from,to;i<n;i++){
109         from=read(),to=read();
110         a_ed(from,to);
111     }
112     memset(mx,-inf,(n+1)<<2);
113     for(rint i=1;i<=n;i++){
114         val[i]=read();
115         su[i]=mx[i]=val[i];
116     }
117     dfs(1,0);
118     char opt[10];  int x,y;
119     m=read();
120     while(m--){
121         scanf("%s",opt);
122         x=read(),y=read();
123         switch(opt[1]){
124             case ‘H‘:{
125                 acc(x);
126                 splay(x);
127                 val[x]=y;
128                 push_up(x);
129                 break;
130             }
131             case ‘M‘:{
132                 split(x,y);
133                 printf("%d\n",mx[y]);
134                 break;
135             }
136             default:{
137                 split(x,y);
138                 printf("%d\n",su[y]);
139                 break;
140             }
141         }
142     }
143     return 0;
144 }
时间: 2024-10-05 05:02:12

luoguP2590 [ZJOI2008]树的统计 [树链剖分] [TLE的LCT]的相关文章

kyeremal-bzoj1036[ZJOI2008]-树的统计count-树链剖分

bzoj1036[ZJOI2008]-树的统计count 1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec  Memory Limit: 162 MB Submit: 7567  Solved: 3109 [Submit][Status][Discuss] Description 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. QM

树的统计Count---树链剖分

NEFU专项训练十和十一——树链剖分 Description 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 III. QSUM u v: 询问从点u到点v的路径上的节点的权值和 注意:从点u到点v的路径上的节点包括u和v本身 Input 输入的第一行为一个整数n,表示节点的个数.接下来n – 1行,每行2个整

zjoi 2008 树的统计——树链剖分

比较基础的一道树链剖分的题 大概还是得说说思路 树链剖分是将树剖成很多条链,比较常见的剖法是按儿子的size来剖分,剖分完后对于这课树的询问用线段树维护--比如求路径和的话--随着他们各自的链向上走,直至他们在同一条链上为止.比较像lca的方法,只不过这里是按链为单位,而且隔壁的SymenYang说可以用树链剖分做lca..吓哭 然后说说惨痛的调题经历:边表一定要开够啊! 不是n-1 而是2*(n-1)啊! 然后写变量时原始值和映射值要搞清楚啊! 不要搞错了! 还有就是下次求最小值一定看清下界是

BZOJ 1036 树的统计-树链剖分

[ZJOI2008]树的统计Count Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 12904 Solved: 5191[Submit][Status][Discuss]Description 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 III. QSUM

[ZJOI2008]树的统计 (树链剖分)

题目描述 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w. 我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 III. QSUM u v: 询问从点u到点v的路径上的节点的权值和 注意:从点u到点v的路径上的节点包括u和v本身 输入输出格式 输入格式: 输入文件的第一行为一个整数n,表示节点的个数. 接下来n – 1行,每行2个整数a和b,表示节点a和节点b之

【BZOJ 1036】【ZJOI 2008】树的统计 树链剖分模板题

sth神犇的模板: //bzoj1036 题目:一个n个点的树每个点有一个权值,支持修改单点权值,求某两点路径上的点权和或最大点权. #include <cstdio> using namespace std; int pos[30001],f[30001],up[30001],son[30001],size[30001],a[80001],next[80001],last[30001],sum[100001],max[100001];//pos是指某点在线段树中的位置:f是父节点:up是所在

[JSOI2008][BZOJ1036] 树的统计 - 树链剖分

Description 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w. 我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 III. QSUM u v: 询问从点u到点v的路径上的节点的权值和 注意:从点u到点v的路径上的节点包括u和v本身 Input & Output Input 输入文件的第一行为一个整数n,表示节点的个数. 接下来n – 1行,每行2个整

【BZOJ 3531】【SDOI 2014】旅行 树链剖分

因为有$10^5$个宗教,需要开$10^5$个线段树. 平时开的线段树是“满”二叉树,但在这个题中代表一个宗教的线段树管辖的区间有很多点都不属于这个宗教,也就不用“把枝叶伸到这个点上”,所以这样用类似主席树的数组动态开点来建立$10^5$个只有几个“树枝”的线段树,维护轻重链就可以了 线段树的$L,R,l,r$弄反了调了好久$QAQ$ $so$ $sad$ #include<cstdio> #include<cstring> #include<algorithm> #d

BZOJ 1036: [ZJOI2008]树的统计Count (树链剖分模板题)

1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 14982  Solved: 6081[Submit][Status][Discuss] Description 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 I