ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

[GDSOI2017]中学生数据结构题(树链剖分+fhq treap)

2020-04-20 20:58:21  阅读:246  来源: 互联网

标签:sz val 剖分 int ll tree 树链 treap top


[GDSOI2017]中学生数据结构题(树链剖分+fhq treap)

题面

给出一棵树,支持三种操作

  1. ADD:路径加
  2. QUERY:路径求和
  3. SHIFT:树上路径整体循环移动一位(如:原路径上的权值依次是:1,4,5,3,操作完后变成:3,1,4,5)

分析

考验数据结构功底和代码能力的好题。似乎有个实现难度更低的LCT解法但没看懂。

考虑序列上的问题,整体循环移动显然很简单,Split出那个跑到前面的数,然后再交换顺序Merge回去。

那么可以树剖,把路径分成\(O(\log n)\)个区间。先考虑从\(x\)到\(lca(x,y)\)的路径,对于每个区间,我们要把区间内的数向左移一位(因为向上走DFS序更小),然后要弹出原来最左边的数,还要把上一个区间弹出来的数插到区间右边。从\(y\)到\(lca(x,y)\)的路径相反。于是可以在非旋Treap里写一个函数进行这些操作,Shift时先跳一遍求出这些区间,然后按路径顺序逐个操作即可。

说起来很简单,但代码有很多细节。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#define maxn 100000
#define maxlogn 20
using namespace std;
template<typename T> void qread(T &x){
	x=0;
	T sign=1;
	char c=getchar();
	while(c<'0'||c>'9'){
		if(c=='-') sign=-1;
		c=getchar();
	}
	while(c>='0'&&c<='9'){
		x=x*10+c-'0';
		c=getchar();
	}
	x=x*sign; 
} 
template<typename T> void qprint(T x){
	if(x<0){
		putchar('-');
		qprint(-x);
	}else if(x==0){
		putchar('0');
		return;
	}else{
		if(x>=10) qprint(x/10);
		putchar('0'+x%10);
	}
}
typedef long long ll;
int n,m;
struct fhq_treap {
#define lson(x) (tree[x].ls)
#define rson(x) (tree[x].rs)
	struct node {
		int ls;
		int rs;
		ll val;
		int dat;
		int sz;
		ll sum;
		ll mark;
		node() {

		}
		node(ll _val) {
			ls=rs=0;
			val=sum=_val;
			dat=rand();
			sz=1;
			mark=0;
		}
	} tree[maxn*maxlogn+5];
	int ptr;
	int root=0;
	int New(ll val) {
		tree[++ptr]=node(val);
		return ptr;
	}
	void push_up(int x) {
		tree[x].sz=tree[lson(x)].sz+1+tree[rson(x)].sz;
		tree[x].sum=tree[lson(x)].sum+tree[x].val+tree[rson(x)].sum;
	}
	void add_tag(int x,ll val) {
		tree[x].val+=val;
		tree[x].sum+=val*tree[x].sz;
		tree[x].mark+=val;
	}
	void push_down(int x) {
		if(tree[x].mark) {
			if(lson(x)) add_tag(lson(x),tree[x].mark);
			if(rson(x)) add_tag(rson(x),tree[x].mark);
			tree[x].mark=0;
		}
	}
	int merge(int x,int y) {
		push_down(x);
		push_down(y);
		if(!x||!y) return x+y;
		if(tree[x].dat<tree[y].dat) {
			lson(y)=merge(x,lson(y));
			push_up(y);
			return y;
		} else {
			rson(x)=merge(rson(x),y);
			push_up(x);
			return x;
		}
	}
	void split(int now,int k,int &x,int &y) {
		if(!now) {
			x=y=0;
			return;
		}
		push_down(now);
		if(k<=tree[lson(now)].sz) {
			y=now;
			split(lson(now),k,x,lson(y));
		} else {
			x=now;
			split(rson(now),k-tree[lson(now)].sz-1,rson(x),y);
		}
		push_up(now);
	}
	void update(int l,int r,ll v) {
		int x,y,z;
		split(root,r,y,z);
		split(y,l-1,x,y);
		add_tag(y,v);
		root=merge(merge(x,y),z);
	}
	ll query(int l,int r) {
		int x,y,z;
		split(root,r,y,z);
		split(y,l-1,x,y);
		ll ans=tree[y].sum;
		root=merge(merge(x,y),z);
		return ans;
	}
	ll lshift(int l,int r,ll v){
		//把[l+1,r]向左移一格,把a[r]设成v,并返回被弹出的a[l]  用于路径上升段(x->lca) 
		int x/*[1,l-1]]*/,y/*l*/,z/*[l+1,r]*/,w/*[r+1,n]*/;
		split(root,r,z,w);
		split(z,l-1,x,z);
		split(z,1,y,z);//注意这里z存的是[l+1,r],所以传参是1而不是l 
		ll ans=tree[y].val;
		root=merge(merge(x,z),merge(New(v),w));
		return ans;
	}
	ll rshift(int l,int r,ll v) { 
		//把[l,r-1]向右移一格,把a[l]设成v,并返回被弹出的a[r]  用于路径下降段(lca->y)
		int x/*[1,l-1]]*/,y/*[l,r-1]*/,z/*r*/,w/*[r+1,n]*/;
		split(root,r,z,w);
		split(z,r-1,y,z);
		split(y,l-1,x,y);
		ll ans=tree[z].val;
		root=merge(merge(x,New(v)),merge(y,w));
		return ans;
	}
	void push_back(ll v){
		root=merge(root,New(v));
	}
} T;

struct edge{
	int from;
	int to;
	int next;
}E[maxn*2+5];
int esz=1;
int head[maxn+5];
void add_edge(int u,int v){
	esz++;
	E[esz].from=u;
	E[esz].to=v;
	E[esz].next=head[u];
	head[u]=esz;
}

int tim;
int deep[maxn+5],sz[maxn+5],fa[maxn+5],son[maxn+5],top[maxn+5],dfn[maxn+5];
void dfs1(int x,int f){
	fa[x]=f;
	deep[x]=deep[f]+1;
	sz[x]=1;
	for(int i=head[x];i;i=E[i].next){
		int y=E[i].to;
		if(y!=f){
			dfs1(y,x);
			sz[x]+=sz[y];
			if(sz[y]>sz[son[x]]) son[x]=y;
		}
	}
}
void dfs2(int x,int t){
	top[x]=t;
	dfn[x]=++tim;
	if(son[x]) dfs2(son[x],t);
	for(int i=head[x];i;i=E[i].next){
		int y=E[i].to;
		if(y!=fa[x]&&y!=son[x]) dfs2(y,y);
	}
}
ll query(int x,int y){
	ll ans=0;
	while(top[x]!=top[y]){
		if(deep[top[x]]<deep[top[y]]) swap(x,y);
		ans+=T.query(dfn[top[x]],dfn[x]);
		x=fa[top[x]];
	} 
	if(deep[x]>deep[y]) swap(x,y);
	ans+=T.query(dfn[x],dfn[y]);
	return ans;
}
void update(int x,int y,int v){
	while(top[x]!=top[y]){
		if(deep[top[x]]<deep[top[y]]) swap(x,y);
		T.update(dfn[top[x]],dfn[x],v);
		x=fa[top[x]];
	} 
	if(deep[x]>deep[y]) swap(x,y);
	T.update(dfn[x],dfn[y],v);
}
void shift(int x,int y){
	static int cnt[2],st[2][maxn+5];//暂存分成的每段区间
	int now=0;//当前处理的重链在哪一段 0:x->lca  1:lca->y 
	int last=T.query(dfn[y],dfn[y]);//把a[y]给路径起点x 
	cnt[0]=cnt[1]=0;
	while(top[x]!=top[y]){
		if(deep[top[x]]<deep[top[y]]){
			swap(x,y);
			now^=1;
		}
		st[now][++cnt[now]]=x;
		x=fa[top[x]];
	} 
	if(deep[x]>deep[y]){
		 swap(x,y);
		 now^=1;
	}
	for(int i=1;i<=cnt[0];i++){
		int u=st[0][i];
		last=T.lshift(dfn[top[u]],dfn[u],last);
	}
	//处理lca那一段
	if(now==0) last=T.rshift(dfn[x],dfn[y],last);
	else last=T.lshift(dfn[x],dfn[y],last);
	for(int i=cnt[1];i>=1;i--){//因为是从下往上跳,而路径是从上往下,要倒序 
		int u=st[1][i];
		last=T.rshift(dfn[top[u]],dfn[u],last);
	} 
}
int main() {
	int u,v,w;
	char cmd[10];
	qread(n);
	for(int i=1;i<n;i++){
		qread(u);
		qread(v);
		add_edge(u,v);
		add_edge(v,u);
	}
	dfs1(1,0);
	dfs2(1,1);
	for(int i=1;i<=n;i++) T.push_back(0);
	qread(m);
	for(int i=1;i<=m;i++){
		scanf("%s",cmd);
		if(cmd[0]=='A'){
			qread(u);
			qread(v);
			qread(w);
			update(u,v,w);
		}else if(cmd[0]=='Q'){
			qread(u);
			qread(v);
			qprint(query(u,v));
			putchar('\n');
		}else{
			qread(u);
			qread(v);
			shift(u,v); 
		}
	}
}
/*
5
1 2
1 3 
3 4
3 5
6
ADD 1 5 2
ADD 3 4 1
QUERY 1 4
SHIFT 1 4
QUERY 3 4
*/ 

标签:sz,val,剖分,int,ll,tree,树链,treap,top
来源: https://www.cnblogs.com/birchtree/p/12740360.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有