Codechef FIBTREE 树链剖分 主席树 LCA 二次剩余 快速幂

原文链接https://www.cnblogs.com/zhouzhendong/p/CC-FIBTREE.html

题目传送门 - CC-FIBTREE

题意

题解

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=100005,S=N*200,mod=1e9+9;
struct Gragh{
	static const int M=N*2;
	int cnt,y[M],nxt[M],fst[N];
	void clear(){cnt=0;memset(fst,0,sizeof fst);}
	void add(int a,int b){y[++cnt]=b,nxt[cnt]=fst[a],fst[a]=cnt;}
}g;
int Pow(int x,int y){
	int ans=1;
	for (;y;y>>=1,x=1LL*x*x%mod)
		if (y&1)
			ans=1LL*ans*x%mod;
	return 0;
}
int n,m,V=276601605,V1=691504013,V2=308495997;
int Pow1[N],Pow2[N],Sum1[N],Sum2[N];
int size[N],depth[N],son[N],fa[N][20],in[N],out[N],top[N],p[N],ap[N],Time=0,cnp=0;
void Get_Gen_Info(int x,int pre,int d){
	size[x]=1,son[x]=-1,depth[x]=d,fa[x][0]=pre;
	for (int i=1;i<20;i++)
		fa[x][i]=fa[fa[x][i-1]][i-1];
	for (int i=g.fst[x];i;i=g.nxt[i])
		if (g.y[i]!=pre){
			int y=g.y[i];
			Get_Gen_Info(y,x,d+1);
			size[x]+=size[y];
			if (son[x]==-1||size[y]>size[son[x]])
				son[x]=y;
		}
}
void Get_Top(int x,int Top){
	in[x]=++Time,ap[p[x]=++cnp]=x,top[x]=Top;
	if (son[x]!=-1)
		Get_Top(son[x],Top);
	for (int i=g.fst[x];i;i=g.nxt[i]){
		int y=g.y[i];
		if (y!=son[x]&&y!=fa[x][0])
			Get_Top(y,y);
	}
	out[x]=Time;
}
struct Seg{
	int sum,L1,L2,R1,R2,ls,rs,len;
	int TagV(){return (1LL*(L1+R1)*Sum1[len-1]-1LL*(L2+R2)*Sum2[len-1]+sum)%mod;}
}T[S];
int root[N],tot=0;
int build(int L,int R){
	int rt=++tot;
	T[rt].len=R-L+1;
	if (L==R)
		return rt;
	int mid=(L+R)>>1;
	T[rt].ls=build(L,mid);
	T[rt].rs=build(mid+1,R);
	return rt;
}
void update(int prt,int &rt,int L,int R,int xL,int xR,int type,int Lv,int Rv){
	if (rt==0)
		rt=prt;
	if (L>xR||R<xL)
		return;
	if (rt==prt)
		T[rt=++tot]=T[prt];
	if (xL<=L&&R<=xR){
		if (type==0)
			T[rt].L1=(T[rt].L1+Pow1[Lv])%mod,T[rt].L2=(T[rt].L2+Pow2[Lv])%mod;
		else
			T[rt].R1=(T[rt].R1+Pow1[Rv])%mod,T[rt].R2=(T[rt].R2+Pow2[Rv])%mod;
		return;
	}
	int mid=(L+R)>>1,lenL=mid-L+1,lenR=R-mid;
	update(T[prt].ls,T[rt].ls,L,mid,xL,xR,type,Lv,Rv+lenR);
	update(T[prt].rs,T[rt].rs,mid+1,R,xL,xR,type,Lv+lenL,Rv);
	T[rt].sum=(T[T[rt].ls].TagV()+T[T[rt].rs].TagV())%mod;
}
int query(int rt,int L,int R,int xL,int xR,int L1,int L2,int R1,int R2){
	if (L>xR||R<xL)
		return 0;
	L1=(L1+T[rt].L1)%mod,L2=(L2+T[rt].L2)%mod;
	R1=(R1+T[rt].R1)%mod,R2=(R2+T[rt].R2)%mod;
	if (xL<=L&&R<=xR){
		int res=T[rt].sum;
		res=(1LL*(L1+R1)*Sum1[T[rt].len-1]-1LL*(L2+R2)*Sum2[T[rt].len-1]+res)%mod;
		res=(res+mod)%mod;
		return res;
	}
	int mid=(L+R)>>1,lenL=mid-L+1,lenR=R-mid;
	return (query(T[rt].ls,L,mid,xL,xR,L1,L2,1LL*R1*Pow1[lenR]%mod,1LL*R2*Pow2[lenR]%mod)
	    +query(T[rt].rs,mid+1,R,xL,xR,1LL*L1*Pow1[lenL]%mod,1LL*L2*Pow2[lenL]%mod,R1,R2))%mod;
}
int LCA(int x,int y){
	if (depth[x]<depth[y])
		swap(x,y);
	for (int i=19;i>=0;i--)
		if (depth[x]-(1<<i)>=depth[y])
			x=fa[x][i];
	if (x==y)
		return x;
	for (int i=19;i>=0;i--)
		if (fa[x][i]!=fa[y][i])
			x=fa[x][i],y=fa[y][i];
	return fa[x][0];
}
void Tupdate(int prt,int &rt,int x,int y){
	int Fx=top[x],Fy=top[y],Tx=0,Ty=0;
	int lca=LCA(x,y),len=depth[x]+depth[y]-depth[lca]*2+1;
	while (Fx!=Fy)
		if (depth[Fx]>depth[Fy]){
			update(prt,rt,1,n,p[Fx],p[x],1,0,Tx+1-(n-p[x]));
			Tx+=depth[x]-depth[Fx]+1;
			x=fa[Fx][0],Fx=top[x];
		}
		else {
			Ty+=depth[y]-depth[Fy]+1;
			update(prt,rt,1,n,p[Fy],p[y],0,len-Ty+1-(p[Fy]-1),0);
			y=fa[Fy][0],Fy=top[y];
		}
	if (depth[x]<depth[y])
		update(prt,rt,1,n,p[x],p[y],0,Tx+1-(p[x]-1),0);
	else
		update(prt,rt,1,n,p[y],p[x],1,0,Tx+1-(n-p[x]));
}
int Tquery(int rt,int x,int y){
	int Fx=top[x],Fy=top[y];
	int ans=0;
	while (Fx!=Fy){
		if (depth[Fx]<depth[Fy])
			swap(x,y),swap(Fx,Fy);
		ans=(ans+query(rt,1,n,p[Fx],p[x],0,0,0,0))%mod;
		x=fa[Fx][0],Fx=top[x];
	}
	if (depth[x]>depth[y])
		swap(x,y);
	ans=(ans+query(rt,1,n,p[x],p[y],0,0,0,0))%mod;
	return ans;
}
int main(){
	scanf("%d%d",&n,&m);
	Pow1[0]=Pow2[0]=1,Sum1[0]=Sum2[0]=1;
	for (int i=1;i<=n;i++){
		Pow1[i]=1LL*Pow1[i-1]*V1%mod,Sum1[i]=(Sum1[i-1]+Pow1[i])%mod;
		Pow2[i]=1LL*Pow2[i-1]*V2%mod,Sum2[i]=(Sum2[i-1]+Pow2[i])%mod;
	}
	g.clear();
	for (int i=1,a,b;i<n;i++){
		scanf("%d%d",&a,&b);
		g.add(a,b);
		g.add(b,a);
	}
	Get_Gen_Info(1,0,0);
	Get_Top(1,1);
	memset(T,0,sizeof T);
	root[0]=build(1,n);
	int LASTANS=0;
	for (int i=1;i<=m;i++){
		char opt[5];
		int x,y;
		scanf("%s%d",opt+1,&x);
		x^=LASTANS;
		root[i]=root[i-1];
		if (opt[1]==‘A‘){
			scanf("%d",&y);
			Tupdate(root[i-1],root[i],x,y);
		}
		if (opt[1]==‘R‘)
			root[i]=root[x];
		if (opt[1]==‘Q‘&&opt[2]==‘S‘){
			scanf("%d",&y);
			if (x==y){
				LASTANS=query(root[i],1,n,1,n,0,0,0,0);
				LASTANS=(1LL*LASTANS*V%mod+mod)%mod;
				printf("%d\n",LASTANS);
			}
			else if (in[y]<=in[x]&&out[x]<=out[y]){
				for (int j=19;j>=0;j--)
					if (depth[x]-(1<<j)>depth[y])
						x=fa[x][j];
				LASTANS=query(root[i],1,n,1,n,0,0,0,0)-query(root[i],1,n,in[x],out[x],0,0,0,0);
				LASTANS=(1LL*LASTANS*V%mod+mod)%mod;
				printf("%d\n",LASTANS);
			}
			else {
				LASTANS=query(root[i],1,n,in[y],out[y],0,0,0,0);
				LASTANS=(1LL*LASTANS*V%mod+mod)%mod;
				printf("%d\n",LASTANS);
			}
		}
		if (opt[1]==‘Q‘&&opt[2]==‘C‘){
			scanf("%d",&y);
			LASTANS=Tquery(root[i],x,y);
			LASTANS=(1LL*LASTANS*V%mod+mod)%mod;
			printf("%d\n",LASTANS);
		}
	}
	return 0;
}

  

原文地址:https://www.cnblogs.com/zhouzhendong/p/CC-FIBTREE.html

时间: 2024-11-12 21:17:46

Codechef FIBTREE 树链剖分 主席树 LCA 二次剩余 快速幂的相关文章

hdu 6162 Ch’s gift(树链剖分+主席树)

题目链接:hdu 6162 Ch's gift 题意: 给你一棵树,树上每个点有一个权值,现在有m个询问,每次询问给你一个s,t,L,R,问你从s到t的路径上,权值在[L,R]内的总和为多少. 题解: 我感觉我写复杂了,用树链剖分来维护路径,然后用主席树来建立权值线段树乱搞. 1 #include<bits/stdc++.h> 2 #define mst(a,b) memset(a,b,sizeof(a)) 3 #define F(i,a,b) for(int i=(a);i<=(b);

BZOJ1146 [CTSC2008]网络管理Network 树链剖分 主席树 树状数组

欢迎访问~原文出处--博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ1146 题意概括 在一棵树上,每一个点一个权值. 有两种操作: 1.单点修改 2.询问两点之间的树链上的第k大值 题解 水题. 就是烦了一点. 树链剖分+带修主席树. 带修主席树: BZOJ1901 Zju2112 Dynamic Rankings 主席树 代码 #include <cstring> #include <cstdio> #include <algorithm&g

BZOJ3531 SDOI2014 旅行 - 树链剖分,主席树

题意:给定一棵树,树上每个点有权值和类型.支持:修改某个点的类型:修改某个点的权值:询问某条链上某个类型的点的和/最大值.点数/类型数/询问数<=100000. 分析: 树链剖分,对每个类型的点建立线段树(动态开点). note: 忘记写t_query返回值调半天-- 莫名其妙地1A 代码: 1 #include <bits/stdc++.h> 2 using namespace std; 3 4 int a[5000005],s[5000005],dep[100005],size[10

[BZOJ 4012][HNOI2015]开店(树链剖分+主席树)

Description 风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到人生哲学.最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点钱.这样的想法当然非常好啦,但是她们也发现她们面临着一个问题,那就是店开在哪里,面向什么样的人群.很神奇的是,幻想乡的地图是一个树形结构,幻想乡一共有 n个地方,编号为 1 到 n,被 n-1 条带权的边连接起来.每个地方都住着一个妖怪,其中第 i 个地方的妖怪年龄是 x_i.妖怪都是些比较喜欢安静的家伙,所以它们并不希望和很多妖怪相邻.所以这

bzoj2588 -- 树链剖分+主席树

先将权值离散. 显然可以对于每个结点建一棵权值线段树存这个点到根结点的路径上的点权,询问时在线段树上二分,但这样时间是O(n2log2n)的. 然后想到用主席树优化,时间复杂度O(n*log2n). 代码: 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<vector> 6 using namespace st

2019年ICPC南昌网络赛 J. Distance on the tree 树链剖分+主席树

边权转点权,每次遍历到下一个点,把走个这条边的权值加入主席树中即可. #include<iostream> #include<algorithm> #include<stdio.h> #include<string.h> using namespace std; const int maxx = 2e5+10; struct node{ int l,r,cnt; }tree[maxx*40]; int head[maxx],rk[maxx],siz[maxx

【BZOJ】1146: [CTSC2008]网络管理Network(树链剖分+线段树套平衡树+二分 / dfs序+树状数组+主席树)

第一种做法(时间太感人): 这题我真的逗了,调了一下午,疯狂造数据,始终找不到错. 后来发现自己sb了,更新那里没有打id,直接套上u了.我.... 调了一下午啊!一下午的时光啊!本来说好中午A掉去学习第二种做法,噗 好吧,现在第一种做法是hld+seg+bst+二分,常数巨大,log^4级别,目前只会这种. 树剖后仍然用线段树维护dfs序区间,然后在每个区间建一颗平衡树,我用treap,(这题找最大啊,,,囧,并且要注意,这里的rank是比他大的数量,so,我们在二分时判断要判断一个范围,即要

Aizu 2450 Do use segment tree 树链剖分+线段树

Do use segment tree Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://www.bnuoj.com/v3/problem_show.php?pid=39566 Description Given a tree with n (1 ≤ n ≤ 200,000) nodes and a list of q (1 ≤ q ≤ 100,000) queries, process the queries in order and out

BZOJ2243 [SDOI2011]染色(树链剖分+线段树合并)

题目链接 BZOJ2243 树链剖分+线段树合并 线段树合并的一些细节需要注意一下 #include <bits/stdc++.h> using namespace std; #define rep(i, a, b) for (int i(a); i <= (b); ++i) #define dec(i, a, b) for (int i(a); i >= (b); --i) typedef long long LL; const int N = 100010; int n, m,