首页 > 代码库 > BZOJ 题目1036: [ZJOI2008]树的统计Count(Link Cut Tree,改动点权求两个最大值和最大值)
BZOJ 题目1036: [ZJOI2008]树的统计Count(Link Cut Tree,改动点权求两个最大值和最大值)
1036: [ZJOI2008]树的统计Count
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 8421 Solved: 3439
[Submit][Status][Discuss]
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个整数a和b,表示节点a和节点b之间有一条边相连。接下来n行,每行一个整数,第i行的整数wi表示节点i的权值。
接下来1行,为一个整数q,表示操作的总数。接下来q行,每行一个操作。以“CHANGE u t”或者“QMAX u v”或者“QSUM u v”的形式给出。 对于100%的数据,保证1<=n<=30000,0<=q<=200000;中途操作中保证每一个节点的权值w在-30000到30000之间。
Output
对于每一个“QMAX”或者“QSUM”的操作,每行输出一个整数表示要求输出的结果。
Sample Input
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
Sample Output
1
2
2
10
6
5
6
5
16
HINT
Source
树的分治
ac代码
/************************************************************** Problem: 1036 User: kxh1995 Language: C++ Result: Accepted Time:3540 ms Memory:13000 kb ****************************************************************/ #include<stdio.h> #include<string.h> #include<queue> #include<iostream> #define INF 0x7fffffff #define max(a,b) (a>b?a:b) using namespace std; int vis[200050]; struct LCT { int bef[200050],pre[200050],next[200050][2],sum[200050],key[200050],val[200050]; void init() { memset(pre,0,sizeof(pre)); memset(next,0,sizeof(next)); val[0]=-INF; sum[0]=0; } void pushup(int x) { sum[x]=key[x]+sum[next[x][1]]+sum[next[x][0]]; val[x]=max(key[x],max(val[next[x][1]],val[next[x][0]])); } void rotate(int x,int kind) { int y,z; y=pre[x]; z=pre[y]; next[y][!kind]=next[x][kind]; pre[next[x][kind]]=y; next[z][next[z][1]==y]=x; pre[x]=z; next[x][kind]=y; pre[y]=x; pushup(y); } void splay(int x) { int rt; for(rt=x;pre[rt];rt=pre[rt]); if(x!=rt) { bef[x]=bef[rt]; bef[rt]=0; while(pre[x]) { if(next[pre[x]][0]==x) { rotate(x,1); } else rotate(x,0); } pushup(x); } } void access(int x) { int fa; for(fa=0;x;x=bef[x]) { splay(x); pre[next[x][1]]=0; bef[next[x][1]]=x; next[x][1]=fa; pre[fa]=x; bef[fa]=0; fa=x; pushup(x); } } void change(int x,int y) { key[x]=y; splay(x); } int query(int x,int y,int flag) { access(y); for(y=0;x;x=bef[x]) { splay(x); if(!bef[x]) { if(flag) return max(key[x],max(val[next[x][1]],val[y])); else return key[x]+sum[next[x][1]]+sum[y]; } pre[next[x][1]]=0; bef[next[x][1]]=x; next[x][1]=y; pre[y]=x; bef[y]=0; y=x; pushup(x); } return 0; } }lct; struct s { int u,v,next; }edge[200020<<1]; int head[200020],cnt; void add(int u,int v) { edge[cnt].u=u; edge[cnt].v=v; edge[cnt].next=head[u]; head[u]=cnt++; } void bfs(int u) { int i,y; queue<int>q; memset(vis,0,sizeof(vis)); vis[u]=1; q.push(u); while(!q.empty()) { u=q.front(); q.pop(); for(int i=head[u];i!=-1;i=edge[i].next) { int v=edge[i].v; if(!vis[v]) { lct.bef[v]=u; vis[v]=1; q.push(v); } } } } int main() { int n; while(scanf("%d",&n)!=EOF) { int i; memset(head,-1,sizeof(head)); cnt=1; lct.init(); for(i=1;i<n;i++) { int u,v; scanf("%d%d",&u,&v); add(u,v); add(v,u); } for(i=1;i<=n;i++) { int x; scanf("%d",&x); lct.key[i]=x; } bfs(1); int q; scanf("%d",&q); while(q--) { char str[10]; int x,y; scanf("%s%d%d",str,&x,&y); if(!strcmp(str,"QMAX")) { printf("%d\n",lct.query(x,y,1)); } else if(!strcmp(str,"QSUM")) { printf("%d\n",lct.query(x,y,0)); } else lct.change(x,y); } } }
BZOJ 题目1036: [ZJOI2008]树的统计Count(Link Cut Tree,改动点权求两个最大值和最大值)