zoukankan      html  css  js  c++  java
  • 【BZOJ 1036】【ZJOI 2008】树的统计 树链剖分模板题

    sth神犇的模板:

    //bzoj1036 题目:一个n个点的树每个点有一个权值,支持修改单点权值,求某两点路径上的点权和或最大点权。
    #include <cstdio>
    using namespace std;
    int pos[30001],f[30001],up[30001],son[30001],size[30001],a[80001],next[80001],last[30001],sum[100001],max[100001];//pos是指某点在线段树中的位置;f是父节点;up是所在链的最上端;son是众儿子中在同一链中的那一个;size是子树的点数;sum是线段树区间和;max是线段树区间最大值
    int n,mm,tot,deep[30001],w[30001],q,que,ll,rr,mmax,ssum,which[30001];
    char c;//w是单点权值;which是线段树某位置对应的是哪个点,可看做与pos双向映射。
    void build(int x,int y)
    {
    	a[++mm]=y;
    	next[mm]=last[x];
    	last[x]=mm;
    	a[++mm]=x;
    	next[mm]=last[y];
    	last[y]=mm;
    }
    void dfs1(int x)
    {
    	int j,mmax=0,num=0;
    	size[x]=1;
    	for (j=last[x];j;j=next[j]) if (a[j]!=f[x])
    	{
    		f[a[j]]=x;
    		deep[a[j]]=deep[x]+1;
    		dfs1(a[j]);
    		size[x]+=size[a[j]];
    		if (size[a[j]]>mmax) {mmax=size[a[j]]; num=a[j];}
    	}
    	son[x]=num;
    }
    void dfs2(int x)
    {
    	pos[x]=++tot;
    	which[tot]=x;
    	if (!son[x]) return;
    	up[son[x]]=up[x];
    	dfs2(son[x]);
    	int j;
    	for (j=last[x];j;j=next[j]) if (a[j]!=f[x]&&a[j]!=son[x])
    	{
    		up[a[j]]=a[j];
    		dfs2(a[j]);
    	}
    }
    void buildtree(int now,int l,int r)
    {
    	if (l==r)
    	{
    		sum[now]=max[now]=w[which[l]];
    		return;
    	}
    	int x=now<<1;
    	buildtree(x,l,(l+r)>>1);
    	buildtree(x+1,((l+r)>>1)+1,r);
    	if (max[x]>max[x+1]) max[now]=max[x]; else max[now]=max[x+1];
    	sum[now]=sum[x]+sum[x+1];
    }
    void change(int now,int l,int r)
    {
    	if (l==r)
    	{
    		max[now]=sum[now]=rr;
    		return;
    	}
    	int mid=(l+r)>>1,x=now<<1;
    	if (ll<=mid) change(x,l,mid); else change(x+1,mid+1,r);
    	if (max[x]>max[x+1]) max[now]=max[x]; else max[now]=max[x+1];
    	sum[now]=sum[x]+sum[x+1];
    }
    void getans(int now,int l,int r)
    {
    	if (l>=ll&&r<=rr)
    	{
    		if (max[now]>mmax) mmax=max[now];
    		ssum+=sum[now];
    		return;
    	}
    	int mid=(l+r)>>1;
    	if (ll<=mid) getans(now<<1,l,mid);
    	if (rr>mid) getans((now<<1)+1,mid+1,r);
    }
    int main()
    {
    	freopen("lx.in","r",stdin);
    	freopen("lx.out","w",stdout);
    	scanf("%d",&n);
    	int i,x,y,tmp;
    	for (i=1;i<n;i++)
    	{
    		scanf("%d%d",&x,&y);
    		build(x,y);
    	}
    	deep[1]=1;
    	dfs1(1);
    	up[1]=1;
    	dfs2(1);
    	for (i=1;i<=n;i++) scanf("%d",&w[i]);
    	buildtree(1,1,n);
    	scanf("%d
    ",&que);
    	for (q=1;q<=que;q++)
    	{
    		c=getchar();
    		if (c=='C')
    		{
    			for (i=1;i<=5;i++) c=getchar();
    			scanf("%d%d
    ",&x,&y);//将点x的权值改为r
    			ll=pos[x];
    			rr=y;
    			change(1,1,n);
    		}
    		else
    		{
    			for (i=1;i<=3;i++) c=getchar();
    			scanf("%d%d
    ",&x,&y);
    			mmax=-99999999;
    			ssum=0;
    			while (up[x]!=up[y])
    			{
    				if (deep[up[x]]<deep[up[y]]) {tmp=x; x=y; y=tmp;}
    				ll=pos[up[x]];
    				rr=pos[x];
    				getans(1,1,n);
    				x=f[up[x]];
    			}
    			if (deep[x]>deep[y]) {tmp=x; x=y; y=tmp;}
    			ll=pos[x];
    			rr=pos[y];
    			getans(1,1,n);
    			if (c=='X') printf("%d
    ",mmax);else printf("%d
    ",ssum);
    		}
    	}
    	return 0;
    }
    

    链剖,xyx说是链抛。给xyx神犇跪了O)Z

    不说了,(;′⌒`)这是我的链剖模板。为何在codevs上总是RE?我对codevs逐渐产生了隔膜。

    #include<cmath>
    #include<cctype>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define for1(i,a,n) for(int i=(a);i<=(n);++i)
    #define for2(i,a,n) for(int i=(a);i<(n);++i)
    #define for3(i,a,n) for(int i=(a);i>=(n);--i)
    #define for4(i,a,n) for(int i=(a);i>(n);--i)
    #define CC(i,a) memset(i,a,sizeof(i))
    using namespace std;
    inline const int max(const int &a,const int &b){return a>b?a:b;}
    inline const int min(const int &a,const int &b){return a<b?a:b;}
    inline void swapp(int &a,int &b){int c=a;a=b;b=c;}
    struct node{int nxt,to;}E[80003];
    int N,point[30003],sum[100003],ma[100003],cnt=1,son[30003],up[30003],size[30003],deep[30003];
    int pos[30003],which[30003],tot=0,a[30003],fa[30003];
    inline void insect(int x,int y){E[cnt].nxt=point[x];E[cnt].to=y;point[x]=cnt++;}
    inline void dfs1(int x){
    	int nmax=0,num=0;
    	size[x]=1;
    	for(int tmp=point[x];tmp;tmp=E[tmp].nxt)if (E[tmp].to!=fa[x]){
    		fa[E[tmp].to]=x;
    		deep[E[tmp].to]=deep[x]+1;
    		dfs1(E[tmp].to);
    		size[x]+=size[E[tmp].to];
    		if (size[E[tmp].to]>nmax){nmax=size[E[tmp].to];num=E[tmp].to;}
    	}son[x]=num;
    }
    inline void dfs2(int x){
    	pos[x]=++tot;which[tot]=x;
    	if (!son[x]) return;
    	up[son[x]]=up[x];
    	dfs2(son[x]);
    	for(int tmp=point[x];tmp;tmp=E[tmp].nxt)if ((E[tmp].to!=fa[x])&&(E[tmp].to!=son[x])){
    		up[E[tmp].to]=E[tmp].to;
    		dfs2(E[tmp].to);
    	}
    }
    inline void buildtree(int l,int r,int rt){
    	if (l==r){sum[rt]=ma[rt]=a[which[l]];return;}
    	int mid=(l+r)>>1;
    	buildtree(l,mid,rt<<1);
    	buildtree(mid+1,r,rt<<1|1);
    	sum[rt]=sum[rt<<1]+sum[rt<<1|1];
    	ma[rt]=max(ma[rt<<1],ma[rt<<1|1]);
    }
    inline void change(int ll,int rr,int l,int r,int rt){
    	if (l==r){sum[rt]=ma[rt]=rr;return;}
    	int mid=(l+r)>>1;
    	if (ll<=mid) change(ll,rr,l,mid,rt<<1);
    	else change(ll,rr,mid+1,r,rt<<1|1);
    	sum[rt]=sum[rt<<1]+sum[rt<<1|1];
    	ma[rt]=max(ma[rt<<1],ma[rt<<1|1]);
    }
    inline int getmax(int L,int R,int l,int r,int rt){
    	if ((L<=l)&&(r<=R)){return ma[rt];}
    	int mid=(l+r)>>1,s=-1E9;
    	if (L<=mid) s=getmax(L,R,l,mid,rt<<1);
    	if (R>mid) s=max(s,getmax(L,R,mid+1,r,rt<<1|1));
    	return s;
    }
    inline void query1(int x,int y){
    	int mmax=-1E9;
    	while (up[x]!=up[y]){
    		if (deep[up[x]]<deep[up[y]])swapp(x,y);
    		mmax=max(mmax,getmax(pos[up[x]],pos[x],1,N,1));
    		x=fa[up[x]];
    	}
    	if (deep[x]>deep[y])swapp(x,y);
    	mmax=max(mmax,getmax(pos[x],pos[y],1,N,1));
    	printf("%d
    ",mmax);
    }
    inline int getsum(int L,int R,int l,int r,int rt){
    	if ((L<=l)&&(r<=R)){return sum[rt];}
    	int mid=(l+r)>>1,s=0;
    	if (L<=mid)s+=getsum(L,R,l,mid,rt<<1);
    	if (R>mid)s+=getsum(L,R,mid+1,r,rt<<1|1);
    	return s;
    }
    inline void query2(int x,int y){
    	int ssum=0;
    	while (up[x]!=up[y]){
    		if (deep[up[x]]<deep[up[y]])swapp(x,y);
    		ssum+=getsum(pos[up[x]],pos[x],1,N,1);
    		x=fa[up[x]];
    	}
    	if (deep[x]>deep[y])swapp(x,y);
    	ssum+=getsum(pos[x],pos[y],1,N,1);
    	printf("%d
    ",ssum);
    }
    int main(){
    	scanf("%d
    ",&N);
    	CC(point,0);CC(deep,0);CC(size,0);CC(sum,0);CC(ma,0);CC(up,0);CC(son,0);CC(fa,0);
    	for2(i,1,N){
    		int x,y;scanf("%d%d
    ",&x,&y);
    		insect(x,y);insect(y,x);
    	}deep[1]=1;
    	dfs1(1);
    	up[1]=1;
    	dfs2(1);
    	for1(i,1,N) scanf("%d",&a[i]);
    	buildtree(1,N,1);
    	int que;scanf("%d
    ",&que);
    	while (que--){
    		char c=getchar();
    		if (c=='C'){
    			for1(i,1,5)c=getchar();
    			int ll,rr;scanf("%d%d
    ",&ll,&rr);
    			change(pos[ll],rr,1,N,1);
    		}else{
    			for1(i,1,3)c=getchar();
    			int x,y;scanf("%d%d
    ",&x,&y);
    			if (c=='X') query1(x,y);
    			else query2(x,y);
    		}
    	}return 0;
    }
    

      这样就可以了呢,第一次用CA爷的电脑,键盘真好使。

  • 相关阅读:
    C# 枚举帮助类EnumHelper(获取描述、名称和数值)
    C# RSA非对称加密、解密及格式转换
    C# RSA加密解密及RSA签名和验证
    SQL Server 帐号权限管理及编程应用(图解)
    C# LINQ之IEqualityComparer<>接口应用
    SQL Server 表变量和临时表的区别
    SQL Server 图解备份(完全备份、差异备份、增量备份)和还原
    OpenLDAP服务器的搭建
    openstack外接ceph
    openstack
  • 原文地址:https://www.cnblogs.com/abclzr/p/5204852.html
Copyright © 2011-2022 走看看