动态树||树链剖分(BZOJ1036)
来源:互联网 发布:c语言 char负值 编辑:程序博客网 时间:2024/06/06 06:46
1036: [ZJOI2008]树的统计Count
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 7051 Solved: 2872
[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
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 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
4
1
2
2
10
6
5
6
5
16
1
2
2
10
6
5
6
5
16
HINT
Source
树的分治
思路:因为操作的是点权。所以可以直接把其中一个变成根,然后接着搞,要是边权的话,就不行了,就要按照LCA那样高了
这个题也可以用树链剖分写
#include<iostream>#include<cstdio>#include<string>#include<cstring>#include<vector>#include<cmath>#include<queue>#include<stack>#include<map>#include<set>#include<algorithm>using namespace std;const int maxn=30010;const int INF=1000000000;int N,Q;struct node{ int v,next;}edge[maxn*2];int head[maxn];int tot;void add_edge(int u,int v){ edge[tot].v=v; edge[tot].next=head[u]; head[u]=tot++;}struct LCT{ int ch[maxn][2],pre[maxn],key[maxn]; int rev[maxn],maxv[maxn]; bool rt[maxn]; int sum[maxn]; void update_rev(int r) { if(!r)return; swap(ch[r][0],ch[r][1]); rev[r]^=1; } void pushdown(int r) { if(rev[r]) { update_rev(ch[r][1]); update_rev(ch[r][0]); rev[r]=0; } } void pushup(int r) { maxv[r]=max(max(maxv[ch[r][0]],maxv[ch[r][1]]),key[r]); sum[r]=sum[ch[r][0]]+sum[ch[r][1]]+key[r]; } void rotate(int x) { int y=pre[x],kind=ch[y][1]==x; ch[y][kind]=ch[x][!kind]; pre[ch[y][kind]]=y; pre[x]=pre[y]; pre[y]=x; ch[x][!kind]=y; if(rt[y])rt[y]=false,rt[x]=true; else ch[pre[x]][ch[pre[x]][1]==y]=x; pushup(y); } //将根节点到r的路径上的所有及诶单的标记下方 void P(int r) { if(!rt[r])P(pre[r]); pushdown(r); } void Splay(int r) { P(r); while(!rt[r]) { int f=pre[r],ff=pre[f]; if(rt[f])rotate(r); else if((ch[ff][1]==f)==(ch[f][1]==r)) rotate(f),rotate(r); else rotate(r),rotate(r); } pushup(r); } int Access(int x) { int y=0; for(;x;x=pre[y=x]) { Splay(x); rt[ch[x][1]]=true,rt[ch[x][1]=y]=false; pushup(x); } return y; } int getroot(int x) { Access(x); Splay(x); while (ch[x][0]) x = ch[x][0]; return x; } //判断是否同根 bool judge(int u,int v) { while(pre[u])u=pre[u]; while(pre[v])v=pre[v]; return u==v; } //将r变成他所在根 void mroot(int r) { Access(r); Splay(r); update_rev(r); } //调用后u是原来u和v的lca,v和ch[u][1]分别存折lca的两个儿子 void lca(int &u,int &v) { Access(v),v=0; while(u) { Splay(u); if(!pre[u])return; rt[ch[u][1]]=true; rt[ch[u][1]=v]=false; pushup(u); u=pre[v=u]; } } //将u合并到v上 void link(int u,int v) { mroot(u); pre[u]=v; } //将v和他的父节点分离 void cut(int v) { //mroot(v); Access(v); Splay(v); pre[ch[v][0]]=0; pre[v]=0; rt[ch[v][0]]=true; ch[v][0]=0; pushup(v); } void init() { memset(head,-1,sizeof(head)); memset(pre,0,sizeof(pre)); memset(ch,0,sizeof(ch)); memset(rev,0,sizeof(rev)); memset(sum,0,sizeof(sum)); for(int i=0;i<=N;i++)rt[i]=true; maxv[0]=-INF; } void dfs(int u,int f) { for(int i=head[u];i!=-1;i=edge[i].next) { int v=edge[i].v; if(v==f)continue; pre[v]=u; dfs(v,u); } }}tree;int main(){ int u,v; char op[10]; while(scanf("%d",&N)!=EOF) { tree.init(); for(int i=1;i<N;i++) { scanf("%d%d",&u,&v); add_edge(u,v); add_edge(v,u); } for(int i=1;i<=N;i++)scanf("%d",&tree.key[i]); tree.dfs(1,0); scanf("%d",&Q); while(Q--) { scanf("%s%d%d",op,&u,&v);//cout<<op<<endl; if(op[0]=='C') { tree.Access(u); tree.Splay(u); tree.key[u]=v; tree.pushup(u); } else if(op[1]=='M') { //注意一下三个操作的顺序 tree.mroot(u); tree.Access(v); tree.Splay(u); printf("%d\n",tree.maxv[u]); } else { tree.mroot(u); tree.Access(v); tree.Splay(u); //tree.Splay(v); printf("%d\n",tree.sum[u]); } } } return 0;}
树链剖分写发(转自http://www.cnblogs.com/silver-bullet/archive/2013/02/09/2909473.html):
#include<cstdio>#include<cstring>#include<algorithm>#define N 30010#define lson l,m,n<<1#define rson m+1,r,n<<1|1using namespace std;const int inf=1<<30;struct Edge{ int u,v,next; Edge(){} Edge(int _u,int _v,int _next){ u=_u;v=_v;next=_next; }}edge[N<<1];int head[N],cnt;int sz[N],top[N],fa[N],dep[N],hash[N],w[N],son[N],num;void init(){ memset(head,-1,sizeof(head)); cnt=num=0;}void add(int u,int v){ edge[cnt]=Edge(u,v,head[u]);head[u]=cnt++; edge[cnt]=Edge(v,u,head[v]);head[v]=cnt++;}void dfs(int u,int d){ sz[u]=1;son[u]=0;dep[u]=d; for(int k=head[u];k!=-1;k=edge[k].next){ int v=edge[k].v; if(v==fa[u])continue; fa[v]=u; dfs(v,d+1); sz[u]+=sz[v]; if(sz[v]>sz[son[u]])son[u]=v; }}void build_tree(int u,int pre){ hash[u]=++num;top[u]=pre; if(son[u])build_tree(son[u],pre); for(int k=head[u];k!=-1;k=edge[k].next){ int v=edge[k].v; if(v!=fa[u]&&v!=son[u])build_tree(v,v); }}struct segtree{ int maxn[N<<2],sum[N<<2]; void pushup(int n){ sum[n]=sum[n<<1]+sum[n<<1|1]; maxn[n]=max(maxn[n<<1],maxn[n<<1|1]); } void update(int nn,int x,int l,int r,int n){ if(l==r){ maxn[n]=sum[n]=x; return; } int m=(l+r)>>1; if(nn<=m)update(nn,x,lson); else update(nn,x,rson); pushup(n); } int query_max(int ll,int rr,int l,int r,int n){ if(ll==l&&rr==r)return maxn[n]; int m=(l+r)>>1; if(rr<=m)return query_max(ll,rr,lson); else if(ll>m)return query_max(ll,rr,rson); else return max(query_max(ll,m,lson),query_max(m+1,rr,rson)); } int query_sum(int ll,int rr,int l,int r,int n){ if(ll==l&&rr==r)return sum[n]; int m=(l+r)>>1; if(rr<=m)return query_sum(ll,rr,lson); else if(ll>m)return query_sum(ll,rr,rson); else return query_sum(ll,m,lson)+query_sum(m+1,rr,rson); }}seg;int Query_max(int a,int b,int n){ int ta=top[a],tb=top[b],ans=-inf; while(ta!=tb){ if(dep[ta]<dep[tb]){ swap(ta,tb);swap(a,b); } ans=max(ans,seg.query_max(hash[ta],hash[a],1,n,1)); a=fa[ta];ta=top[a]; } if(dep[a]>dep[b])swap(a,b); return max(ans,seg.query_max(hash[a],hash[b],1,n,1));}int Query_sum(int a,int b,int n){ int ta=top[a],tb=top[b],ans=0; while(ta!=tb){ if(dep[ta]<dep[tb]){ swap(ta,tb);swap(a,b); } ans+=seg.query_sum(hash[ta],hash[a],1,n,1); a=fa[ta];ta=top[a]; } if(dep[a]>dep[b])swap(a,b); return ans+seg.query_sum(hash[a],hash[b],1,n,1);}int main(){ int n,a,b,q; char op[10]; while(~scanf("%d",&n)){ init(); for(int i=1;i<n;i++){ scanf("%d%d",&a,&b); add(a,b); } for(int i=1;i<=n;i++)scanf("%d",&w[i]); dfs(1,1); build_tree(1,1); for(int i=1;i<=n;i++)seg.update(hash[i],w[i],1,n,1); scanf("%d",&q); while(q--){ scanf("%s%d%d",op,&a,&b); if(strcmp(op,"QMAX")==0){ int ans=Query_max(a,b,n); printf("%d\n",ans); }else if(strcmp(op,"QSUM")==0){ int ans=Query_sum(a,b,n); printf("%d\n",ans); }else { seg.update(hash[a],b,1,n,1); } } } return 0;}
0 0
- 动态树||树链剖分(BZOJ1036)
- 【bzoj1036】[ZJOI2008]树的统计Count(树链剖分)/(动态树)
- bzoj1036 [ZJOI2008]树的统计(树链剖分)
- bzoj1036 树的统计 树链剖分
- BZOJ1036 [ZJOI2008]树的统计Count(树链剖分)
- [BZOJ1036][ZJOI2008]树的统计Count(树链剖分)
- [BZOJ1036][JZOJ2256]【ZJOI2008】树的统计(树链剖分模板)
- [BZOJ1036][ZJOI2008]树的统计Count(树链剖分)
- 树链剖分基础模板(BZOJ1036[ZJOI2008]树的统计Count)
- bzoj1036: [ZJOI2008]树的统计Count(树链剖分)
- [bzoj1036]:[ZJOI2008]树的统计Count(树链剖分)
- [BZOJ1036][ZJOI2008]树的统计Count(树链剖分)
- BZOJ1036 树链剖分
- bzoj1036 (树链剖分)
- BZOJ1036 树的统计Count(LCT动态树)
- bzoj1036树的统计 树链剖分+线段树
- BZOJ1036 [ZJOI2008]树的统计Count 树链剖分
- bzoj1036 codevs2460: [ZJOI2008]树的统计 树链剖分
- 几款开源分词地址
- find -exec 与 xargs的区别与使用
- Java从网络中请求获取JSon数据以及解析JSON数据----(自创,请注明)
- UICollectionViewFlowLayout 和collectionView的api的一些解释
- Java 中synchronized的理解
- 动态树||树链剖分(BZOJ1036)
- 四元数的表示
- 新装ubuntu12.04搜集一些碰到的问题
- 获取mp4文件信息2 - 计算电影图像宽度和高度
- matplotlib画图时的中文设置
- Zygote进程详解
- Java学习笔记之异常
- udp聊天室 带有注册功能
- 自定义ListAdapter使用时,不调用getView()的奇葩问题