BZOJ 1036: [ZJOI2008]树的统计Count
2014-06-13 15:52
417 查看
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
41 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
41
2
2
10
6
5
6
5
16
题解
树链剖分模板。3000多ms。#include<cstdio> #include<cstring> #include<cstdlib> #include<iostream> #include<cmath> using namespace std; int n,zz,head[30002],v[30002]; struct bian {int to,nx;} e[60005]; int h[30002],fa[30002][16],son[30002]; bool vis[30002]; int size,bl[30002],tw[30002]; //belong数组,记录每个点所在链的编号,tw数组表示点i在线段树上的位置* struct shu {int l,r,sum,mx;} tr[120002]; void insert(int x,int y) { zz++; e[zz].to=y; e[zz].nx=head[x]; head[x]=zz; zz++; e[zz].to=x; e[zz].nx=head[y]; head[y]=zz; } void init()//输入1,处理树上的边 { scanf("%d",&n); int x,y; for(int i=1;i<n;i++) {scanf("%d%d",&x,&y); insert(x,y);} for(int i=1;i<=n;i++) scanf("%d",&v[i]); } void dfs1(int x)//处理深度h,和LCA的dfs相同,顺便再处理出每个子树的结点个数。 { vis[x]=1; son[x]=1; for(int i=1;i<=14;i++) {if(h[x]<(1<<i)) break; fa[x][i]=fa[fa[x][i-1]][i-1]; } for(int i=head[x];i;i=e[i].nx) {if(vis[e[i].to]) continue; h[e[i].to]=h[x]+1; fa[e[i].to][0]=x; dfs1(e[i].to); son[x]+=son[e[i].to]; } } void dfs2(int x,int ll/*表示所在链的编号*/)//处理链 { int k=0; size++; tw[x]=size; bl[x]=ll; for(int i=head[x];i;i=e[i].nx) {if(h[e[i].to]>h[x]&&son[e[i].to]>son[k]) k=e[i].to;} if(k==0) return; dfs2(k,ll); for(int i=head[x];i;i=e[i].nx) {if(h[e[i].to]>h[x]&&e[i].to!=k) dfs2(e[i].to,e[i].to);} } void build(int w,int l,int r)//线段树建树 { tr[w].l=l; tr[w].r=r; if(l==r) return; int mid=(l+r)>>1; build(w<<1,l,mid); build((w<<1)+1,mid+1,r); } void change(int w,int x,int y)//权值修改(单点) { if(tr[w].l==tr[w].r) {tr[w].mx=tr[w].sum=y; return;} int mid=(tr[w].l+tr[w].r)>>1; if(x<=mid) change(w<<1,x,y); else change((w<<1)+1,x,y); tr[w].sum=tr[w<<1].sum+tr[(w<<1)+1].sum; tr[w].mx=max(tr[w<<1].mx,tr[(w<<1)+1].mx); } int lca(int x,int y) { if(h[x]<h[y]) swap(x,y); int t=h[x]-h[y]; for(int i=0;i<=14;i++) {if(t&(1<<i)) x=fa[x][i];} for(int i=14;i>=0;i--) {if(fa[x][i]!=fa[y][i]) {x=fa[x][i]; y=fa[y][i];} } if(x==y) return x; else return fa[x][0]; } int getm(int w,int l,int r) { int x=tr[w].l,y=tr[w].r; if(l==x&&r==y) return tr[w].mx; int mid=(x+y)>>1; if(r<=mid) return getm(w<<1,l,r); else if(l>mid) return getm((w<<1)+1,l,r); else return max(getm(w<<1,l,mid),getm((w<<1)+1,mid+1,r)); } int fmax(int x,int y) { int big=-0x7fffffff; while(bl[x]!=bl[y]) {big=max(big,getm(1,tw[bl[x]],tw[x])); x=fa[bl[x]][0]; } big=max(big,getm(1,tw[y],tw[x])); return big; } int gets(int w,int l,int r) { int x=tr[w].l,y=tr[w].r; if(l==x&&y==r)return tr[w].sum; int mid=(x+y)>>1; if(r<=mid)return gets(w<<1,l,r); else if(l>mid)return gets((w<<1)+1,l,r); else return gets(w<<1,l,mid)+gets((w<<1)+1,mid+1,r); } int fsum(int x,int y) { int sum=0; while(bl[x]!=bl[y]) {sum+=gets(1,tw[bl[x]],tw[x]); x=fa[bl[x]][0]; } sum+=gets(1,tw[y],tw[x]); return sum; } void work() { build(1,1,n); for(int i=1;i<=n;i++) change(1,tw[i],v[i]); int k,x,y; char ch[7]; scanf("%d",&k); for(int i=1;i<=k;i++) {scanf("%s%d%d",ch,&x,&y); if(ch[0]=='C') {v[x]=y; change(1,tw[x],y);} else {int t=lca(x,y); //cout<<t<<" "; if(ch[1]=='M') printf("%d\n",max(fmax(x,t),fmax(y,t))); else printf("%d\n",fsum(x,t)+fsum(y,t)-v[t]); } } } int main() { init(); dfs1(1); dfs2(1,1); work(); return 0; }
相关文章推荐
- BZOJ 1036 [ZJOI2008]树的统计 Count 题解&代码
- BZOJ 1036: [ZJOI2008]树的统计Count 【树链剖分】
- [BZOJ1036][ZJOI2008]树的统计Count
- BZOJ 1036 [ZJOI2008]树的统计Count (树链剖分 - 点权剖分 - 单点权修改)
- BZOJ1036 [ZJOI2008]树的统计Count
- BZOJ[1036] [ZJOI2008]树的统计Count 树链剖分模板
- 【bzoj1036】【树链剖分】 [ZJOI2008]树的统计Count
- 【BZOJ 1036】[ZJOI2008]树的统计Count
- BZOJ 1036: [ZJOI2008]树的统计Count [树链剖分]【学习笔记】
- bzoj1036 [ZJOI2008]树的统计Count (树链剖分|Link Cut Tree)
- BZOJ 1036 [ZJOI2008]树的统计Count (树链剖分裸题)
- [ZJOI2008]树的统计Count bzoj1036 树链剖分
- BZOJ 1036: [ZJOI2008]树的统计Count (树链剖分+线段树)
- BZOJ 1036: [ZJOI2008]树的统计Count(树链剖分 点权)
- bzoj1036: [ZJOI2008]树的统计Count 树链剖分+线段树
- [bzoj1036]:[ZJOI2008]树的统计Count(树链剖分)
- BZOJ 1036: [ZJOI2008]树的统计Count(树链剖分(点权))
- 【bzoj1036】[ZJOI2008]树的统计Count(树链剖分)/(动态树)
- 【BZOJ1036】【ZJOI2008】【树的统计count】【树链剖分】
- BZOJ 1036: [ZJOI2008]树的统计Count 树链剖分