BZOJ 3221 [Codechef FEB13] Obserbing the tree树上询问 树链剖分 主席树维护区间加等差数列
来源:互联网 发布:网络教育文凭事业单位 编辑:程序博客网 时间:2024/06/05 08:57
题目大意:给出一棵树,每个结点初始均为0,要求支持以下操作:路径加等差数列,询问路径上结点权值和,回到之前的某个版本,强制在线。
调到吐血。
很明显可以看出需要树链剖分+主席树来解决,由于需要在主席树上区间修改所以标记永久化。
区间维护等差数列需要在每个结点上维护 首项 和 公差。
树链剖分时在路径上加等差数列需要讨论,细节比较多,详见代码。
(我看错题了..注意回到某个版本并不舍弃在这之间的版本)
#include <cstdio>#include <algorithm>#include <cstring>#define N 150005#define int long longusing namespace std;typedef long long LL;int time_clock,tot_time;namespace Segment_Tree { struct Node { Node* ch[2]; int sum,a0,d,l,r,ver; Node(Node* tmp=NULL) { if(tmp) { ch[0]=tmp->ch[0]; ch[1]=tmp->ch[1]; sum=tmp->sum; a0=tmp->a0; d=tmp->d; l=tmp->l; r=tmp->r; ver=tmp->ver; } else { ch[0]=ch[1]=NULL; sum=l=r=a0=d=ver=0; } } void* operator new(size_t) { static Node *C,*mempool; if(C==mempool) mempool=(C=new Node[1<<20])+(1<<20); return C++; } }*root[N]; void init(Node*& o,int l,int r) { o=new Node(); o->l=l, o->r=r; if(l==r) return ; int mid=l+r>>1; init(o->ch[0],l,mid), init(o->ch[1],mid+1,r); return ; } int query(Node* o,int l,int r) { int tmp=(2*o->a0+o->d*(l+r-2*o->l))*(r-l+1)/2; if(o->l==l && o->r==r) return o->sum+tmp; int mid=o->l+o->r>>1; if(r<=mid) return tmp+query(o->ch[0],l,r); if(l>mid) return tmp+query(o->ch[1],l,r); return tmp+query(o->ch[0],l,mid)+query(o->ch[1],mid+1,r); } void change(Node*& o,int l,int r,int a0,int d) { if(o->ver!=time_clock) { Node* tmp=o; o=new Node(tmp); o->ver=time_clock; } if(o->l==l && o->r==r) { o->a0+=a0; o->d+=d; return ; } o->sum+=(2*a0+d*(r-l))*(r-l+1)/2; int mid=o->l+o->r>>1; if(r<=mid) change(o->ch[0],l,r,a0,d); else if(l>mid) change(o->ch[1],l,r,a0,d); else change(o->ch[0],l,mid,a0,d), change(o->ch[1],mid+1,r,a0+d*(mid+1-l),d); return ; }}namespace Tree_Partition { struct Edge { int from,to,nxt; Edge() {} Edge(int _from,int _to,int _nxt):from(_from),to(_to),nxt(_nxt) {} }e[N*2]; int fir[N],tot=-1; void Add_Edge(int x,int y) { e[++tot]=Edge(x,y,fir[x]), fir[x]=tot; e[++tot]=Edge(y,x,fir[y]), fir[y]=tot; return ; } int dfs_clock,pa[N],top[N],dpt[N],siz[N],son[N],pos[N],seq[N]; void dfs1(int x) { siz[x]=1; dpt[x]=dpt[pa[x]]+1; for(int i=fir[x];~i;i=e[i].nxt) { if(e[i].to==pa[x]) continue; pa[e[i].to]=x; dfs1(e[i].to); siz[x]+=siz[e[i].to]; if(siz[son[x]]<siz[e[i].to]) son[x]=e[i].to; } return ; } void dfs2(int x) { pos[x]=++dfs_clock; seq[dfs_clock]=x; if(son[pa[x]]==x) top[x]=top[pa[x]]; else top[x]=x; if(son[x]) dfs2(son[x]); for(int i=fir[x];~i;i=e[i].nxt) { if(e[i].to==pa[x] || e[i].to==son[x]) continue; dfs2(e[i].to); } return ; } int LCA(int x,int y) { while(top[x]!=top[y]) { if(dpt[top[x]]<dpt[top[y]]) swap(x,y); x=pa[top[x]]; } if(dpt[x]<dpt[y]) swap(x,y); return y; } int query(int x,int y) { using Segment_Tree :: query; using Segment_Tree :: root; int ans=0; while(top[x]!=top[y]) { if(dpt[top[x]]<dpt[top[y]]) swap(x,y); ans+=query(root[time_clock],pos[top[x]],pos[x]); x=pa[top[x]]; } if(dpt[x]<dpt[y]) swap(x,y); ans+=query(root[time_clock],pos[y],pos[x]); return ans; } void change(int x,int y,int a0,int d) { using Segment_Tree :: root; using Segment_Tree :: change; tot_time++; root[tot_time]=root[time_clock]; time_clock=tot_time; int lca=LCA(x,y); int an=a0+d*(dpt[x]+dpt[y]-2*dpt[lca]); while(top[x]!=top[y]) { if(dpt[top[x]]>dpt[top[y]]) { change(root[time_clock],pos[top[x]],pos[x],a0+d*(dpt[x]-dpt[top[x]]),-d); a0+=(dpt[x]-dpt[top[x]]+1)*d; x=pa[top[x]]; } else { change(root[time_clock],pos[top[y]],pos[y],an-d*(dpt[y]-dpt[top[y]]),d); an-=(dpt[y]-dpt[top[y]]+1)*d; y=pa[top[y]]; } } if(dpt[x]>dpt[y]) change(root[time_clock],pos[y],pos[x],an,-d); else change(root[time_clock],pos[x],pos[y],a0,d); return ; }}#undef intint main() { #define int long long int n,m; scanf("%lld%lld",&n,&m); using namespace Tree_Partition; memset(fir,-1,sizeof fir); for(int i=1;i<n;i++) { int x,y; scanf("%lld%lld",&x,&y); Add_Edge(x,y); } dfs1(1), dfs2(1); Segment_Tree :: init(Segment_Tree :: root[0],1,n); int last_ans=0; while(m--) { char mode[5]; int x,y,a0,d; scanf("%s",mode); if(mode[0]=='c') { scanf("%lld%lld%lld%lld",&x,&y,&a0,&d); x^=last_ans, y^=last_ans; change(x,y,a0,d); } else if(mode[0]=='q') { scanf("%lld%lld",&x,&y); x^=last_ans, y^=last_ans; printf("%lld\n",last_ans=query(x,y)); } else { scanf("%lld",&x); x^=last_ans; time_clock=x; } } return 0;}
0 0
- BZOJ 3221 [Codechef FEB13] Obserbing the tree树上询问 树链剖分 主席树维护区间加等差数列
- BZOJ 3221: [Codechef FEB13] Obserbing the tree树上询问 树链剖分 主席树
- bzoj 3221: [Codechef FEB13] Obserbing the tree树上询问 (可持久化线段树+树链剖分)
- BZOJ3221 [Codechef FEB13] Obserbing the tree树上询问
- [主席树维护HASH && SET维护DFS序] Codechef. Walks on the binary tree
- Codechef Aug2017 #Walks on the binary tree -- 主席树+Hash
- 【BZOJ 2588】 Spoj 10628. Count on a tree|树上K大|树链剖分|主席树
- bzoj 2588 树上主席树
- [主席树维护HASH] Codechef. Cloning
- 【HDU4348】To The Moon-主席树(可持久化线段树)区间修改+区间询问
- 【BZOJ 1316】 树上的询问 树分治
- 【 bzoj 4299 】 Codechef FRBSUM - 主席树乱搞
- 【BZOJ 4299】 Codechef FRBSUM 主席树
- BZOJ BZOJ 2588: Spoj 10628. Count on a tree 树上主席树
- BZOJ 2588 & SPOJ 10628:树上主席树
- bzoj 2588: Spoj 10628. Count on a tree(树上主席树)
- 【BZOJ 2588】Count on a tree 【树上路径第K大】【LCA+主席树】
- 【BZOJ 2588】Spoj 10628. Count on a tree 主席树+树上差分
- c语言实现打字小游戏
- 负隅顽抗的房价,终于被镇压了
- Linux必学的60个命令(四)
- HIS(Hospital Information System,医院信息系统)简介
- 爬虫框架Scrapy学习记录II--Selector学习
- BZOJ 3221 [Codechef FEB13] Obserbing the tree树上询问 树链剖分 主席树维护区间加等差数列
- 独木舟
- Linux必学的60个命令(五)
- Discuz API&JSON 适用于IOS及Android移动端开发
- RHEL6.4(或CentOS 6)源码安装Git2.9.3
- BGAQRCode-Android的简单使用
- Linux必学的60个命令(六)
- 不用VPN上Google的方法
- sql注入之GET/POST注入