[练习]: 树链剖分练习题

24 篇文章 0 订阅
21 篇文章 0 订阅
这些是一些树剖的基础题 难度从低到高 初学者一定要做一做。。
1.洛谷p3384树链剖分模板
//一定记得任何算值的地方取模。。还有注意add和query时候深度小的在前面!不然线段树会卡死 
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#define ll long long
#define N 100005
#define ls p<<1
#define rs p<<1|1
using namespace std;
int b[2*N],p[N],v[2*N],nt[2*N],fa[N],belong[N],cover[N],pos[N],sz[N],deep[N];
int n,m,w,q,cnt,num;
struct node{int l,r,sum,addv;}t[4*N];
void insert(int x,int y){
	cnt++;b[cnt]=y;nt[cnt]=p[x];p[x]=cnt;
	cnt++;b[cnt]=x;nt[cnt]=p[y];p[y]=cnt;
}
void ini(){
	scanf("%d%d%d%d",&n,&m,&w,&q);
	for(int i=1;i<=n;i++) scanf("%d",&v[i]);
	int x,y;
	for(int i=1;i<n;i++){
		scanf("%d%d",&x,&y);
		insert(x,y);
	}
}
void dfs(int x){
	sz[x]=1;
	for(int e=p[x];e;e=nt[e]){
		int k=b[e];
		if(k!=fa[x])
		{
			deep[k]=deep[x]+1;
			fa[k]=x;
			dfs(k);
			sz[x]+=sz[k];
			cover[x]=max(cover[x],cover[k]);
		}
	}
}
void dfs2(int x,int idno){
	belong[x]=idno;
	num++;
	pos[x]=num;
	cover[x]=num;
	int k=0;
	for(int e=p[x];e;e=nt[e]){
		int kk=b[e];
		if(kk!=fa[x]&&sz[kk]>sz[k])
			k=kk;
	}
	if(k>0){
		dfs2(k,idno);
		cover[x]=max(cover[x],cover[k]);
	}
	for(int e=p[x];e;e=nt[e]){
		int kk=b[e];
		if(kk!=k&&kk!=fa[x]){
			dfs2(kk,kk);
			cover[x]=max(cover[x],cover[kk]);
		}
	}
}
void build(int p,int l,int r){
	t[p].l=l;t[p].r=r;
	if(l==r) return;
	build(p<<1,l,(l+r)/2);
	build(p<<1|1,(l+r)/2+1,r);
}
void pushdown(int p){
	if(t[p].addv!=0){
		t[ls].addv+=t[p].addv;t[ls].addv%=q;
		t[ls].sum+=(t[ls].r-t[ls].l+1)*t[p].addv;t[ls].sum%=q;
		t[rs].addv+=t[p].addv;t[rs].addv%=q;
		t[rs].sum+=(t[rs].r-t[rs].l+1)*t[p].addv;t[rs].sum%=q;
		t[p].addv=0;
	}
}
void pushup(int p){t[p].sum=t[ls].sum+t[rs].sum;t[p].sum%=q;}
void add(int p,int l,int r,int v){
	if(r<l) return ; 
	if(t[p].l==l&&t[p].r==r)
	{t[p].sum+=(t[p].r-t[p].l+1)*v;t[p].addv+=v;t[p].sum%=q;t[p].addv%=q;return;}
	pushdown(p);
	int mid=(t[p].l+t[p].r)>>1;
	if(r<=mid) add(p<<1,l,r,v);
	else if(l>mid) add(p<<1|1,l,r,v);
	else {add(p<<1,l,mid,v);add(p<<1|1,mid+1,r,v);}
	pushup(p);
}
ll  query(int p,int l,int r){
	if(r<l) return 0;
	if(t[p].l==l&&t[p].r==r)
	return t[p].sum%q;
	pushdown(p);
	int mid=(t[p].l+t[p].r)>>1;
	if(r<=mid) query(p<<1,l,r)%q;
	else if(l>mid) query(p<<1|1,l,r)%q;
	else return query(p<<1,l,mid)%q+query(p<<1|1,mid+1,r)%q;
}
ll solvesum(int x,int y){
	ll s=0;
	while(belong[x]!=belong[y]){
		if(deep[belong[x]]<deep[belong[y]]) swap(x,y);
		s+=query(1,pos[belong[x]],pos[x]);s%=q;
		x=fa[belong[x]];
	}
	if(pos[x]>pos[y]) swap(x,y);
	s+=query(1,pos[x],pos[y]);s%=q;
	return s%q;
}
void solveadd(int x,int y,int z){
	while(belong[x]!=belong[y]){
		if(deep[belong[x]]<deep[belong[y]]) swap(x,y);
		add(1,pos[belong[x]],pos[x],z);
		x=fa[belong[x]];
	}
	if(pos[x]>pos[y]) swap(x,y);
	add(1,pos[x],pos[y],z);
}
int main(){
	ini();
	dfs(w);
	dfs2(w,w);
	build(1,1,n);
	for(int i=1;i<=n;i++){
		add(1,pos[i],pos[i],v[i]);
	}
	int f,x,y,z;
	while(m--){
		scanf("%d%d",&f,&x);
		if(f==1){
			scanf("%d%d",&y,&z);
			solveadd(x,y,z%q);
		}
		if(f==2){
			scanf("%d",&y);
			printf("%d\n",solvesum(x,y)%q);
		}
		if(f==3){
			scanf("%d",&z);
			add(1,pos[x],cover[x],z%q);
		}
		if(f==4)
			printf("%d\n",query(1,pos[x],cover[x])%q);
	}
	return 0;
}
2.codevs4633[Mz]树链剖分练习
请忽略这题 因为我没有ac 如果要看树剖的模板请看上篇博客 这题错的原因应该是哪个小地方写错了 但是我懒得写一遍了qwq
//还没有ac 只有20分 以后看到这个博客的时候在补吧 如果有好心人看到 帮我看看错在哪里
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#define N 100005
#define ls p<<1
#define rs p<<1|1
#define ll long long
using namespace std;
int n,m;
int cnt,num;
int head[N],deep[N],belong[N],size[N],fa[N],pos[N];
struct node{int to,next;}e[N<<1];
struct data{int l,r;ll sum,addv;}t[N<<2];
void insert(int x,int y){
	cnt++;e[cnt].to=y;e[cnt].next=head[x];head[x]=cnt;
	cnt++;e[cnt].to=x;e[cnt].next=head[y];head[y]=cnt;
}
void ini(){
	scanf("%d",&n);
	int x,y;
	for(int i=1;i<n;i++){
		scanf("%d%d",&x,&y);
		insert(x,y);
	}
	scanf("%d",&m);
}
void dfs(int x){
	size[x]=1;
	for(int i=head[x];i;i=e[i].next){
		int k=e[i].to;
		if(k!=fa[x]){
			deep[k]=deep[x]+1;
			fa[k]=x;
			dfs(k);
			size[x]+=size[k];
		}
	}
}
void dfs2(int x,int chain){
	num++;
	pos[x]=num;
	belong[x]=chain;
	int k=0;
	for(int i=head[x];i;i=e[i].next){
		int kk=e[i].to;
		if(kk!=fa[x]&&size[kk]>size[k])
			k=kk;
	}
	if(k==0) return;
	dfs2(k,chain);
	for(int i=head[x];i;i=e[i].next){
		int kk=e[i].to;
		if(kk!=fa[x]&&kk!=k)
			dfs2(kk,kk);
	}
}
void build(int p,int l,int r){
	t[p].l=l;t[p].r=r;
	if(l==r) return ;
	int mid=(l+r)>>1;
 	build(ls,l,mid);
 	build(rs,mid+1,r);
} 
void pushdown(int p){
	if(t[p].addv!=0){
		t[ls].addv+=t[p].addv;t[rs].addv+=t[p].addv;
		t[ls].sum+=(t[ls].r-t[ls].l+1)*t[p].addv;
		t[rs].sum+=(t[rs].r-t[rs].l+1)*t[p].addv;
		t[p].addv=0;
	}
}
void pushup(int p){ t[p].sum=t[ls].sum+t[rs].sum;}
void add(int p,int x,int y,ll v){
	if(t[p].l==x&&t[p].r==y){
		t[p].sum+=(t[p].r-t[p].l+1)*v;t[p].addv+=v;return ;
	}
	pushdown(p);
	int mid=(t[p].l+t[p].r)>>1;
	if(y<=mid) add(ls,x,y,v);
	else if(x>mid) add(rs,x,y,v);
	else {
		add(ls,x,mid,v);add(rs,mid+1,y,v);
	}
	pushup(p);
} 
void solveadd(int x,int y,ll v){
	while(belong[x]!=belong[y]){
		if(deep[belong[x]]<deep[belong[y]]) swap(x,y);
		add(1,pos[belong[x]],pos[x],v);
		x=fa[belong[x]];
	}if(pos[x]>pos[y]) swap(x,y);
	add(1,pos[x],pos[y],v);
}
ll query(int p,int x,int y){
	if(t[p].l==x&&t[p].r==y)
	{return t[p].sum;}
	pushdown(p);
	int mid=(t[p].l+t[p].r)>>1;	
	if(y<=mid) return query(ls,x,y);
	else if(x>mid) return query(rs,x,y);
	else return query(ls,x,mid)+query(rs,mid+1,y);
}
ll solvequery(int x,int y){
	int s=0;
	while(belong[x]!=belong[y]){
		if(deep[belong[x]]<belong[y]) swap(x,y);
		s+=query(1,pos[belong[x]],pos[x]);
		x=fa[belong[x]]; 
	}
	if(pos[x]>pos[y]) swap(x,y);
	s+=query(1,pos[x],pos[y]);
	return s;
}
int main(){
	ini();
	dfs(1);
	dfs2(1,1);
	build(1,1,n);
	while(m--){
		int k,x,y;
		scanf("%d%d%d",&k,&x,&y);
		if(k==1) solveadd(x,y,1);
		if(k==2) printf("%lld\n",solvequery(x,y));
	}
	return 0;
} 
3.bzoj1036树的统计Count
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#define inf 0x7fffffff
#define N 30005 
#define M 60005
using namespace std;
int n,q,cnt,sz;
int v[N],dep[N],size[N],head[N],fa[N];
int pos[N],bl[N];
struct data{
	int to,next;
}e[M];
struct seg{
	int l,r,mx,sum;
}t[100005];
void insert(int u,int v)
{
    e[++cnt].to=v;e[cnt].next=head[u];head[u]=cnt;
    e[++cnt].to=u;e[cnt].next=head[v];head[v]=cnt;
}
void ini()
{
    scanf("%d",&n);
    for(int i=1;i<n;i++)
    {
		int x,y;
		scanf("%d%d",&x,&y);
		insert(x,y);
	}
    for(int i=1;i<=n;i++)scanf("%d",&v[i]);
}
void dfs1(int x)
{
    size[x]=1;
    for(int i=head[x];i;i=e[i].next)
    {
        if(e[i].to==fa[x])continue;
        dep[e[i].to]=dep[x]+1;
        fa[e[i].to]=x;
        dfs1(e[i].to);
        size[x]+=size[e[i].to];
    }
}
void dfs2(int x,int chain)
{
    int k=0;sz++;
    pos[x]=sz;
	bl[x]=chain;
    for(int i=head[x];i;i=e[i].next)
        if(dep[e[i].to]>dep[x]&&size[e[i].to]>size[k])
            k=e[i].to;
    if(k==0)return;
    dfs2(k,chain);
    for(int i=head[x];i;i=e[i].next)
        if(dep[e[i].to]>dep[x]&&k!=e[i].to)
            dfs2(e[i].to,e[i].to);
}
void build(int k,int l,int r)
{
    t[k].l=l;t[k].r=r;
    if(l==r)return;
    int mid=(l+r)>>1;
    build(k<<1,l,mid);
    build(k<<1|1,mid+1,r);
}
void change(int k,int x,int y)
{
    int l=t[k].l,r=t[k].r,mid=(l+r)>>1;
    if(l==r){t[k].sum=t[k].mx=y;return;}
    if(x<=mid)change(k<<1,x,y);
    else change(k<<1|1,x,y);
    t[k].sum=t[k<<1].sum+t[k<<1|1].sum;
    t[k].mx=max(t[k<<1].mx,t[k<<1|1].mx);
}
int querysum(int k,int x,int y)
{
    int l=t[k].l,r=t[k].r,mid=(l+r)>>1;
    if(l==x&&y==r)return t[k].sum;
    if(y<=mid)return querysum(k<<1,x,y);
    else if(x>mid)return querysum(k<<1|1,x,y);
    else {return querysum(k<<1,x,mid)+querysum(k<<1|1,mid+1,y);}
}
int querymx(int k,int x,int y)
{
	
    int l=t[k].l,r=t[k].r,mid=(l+r)>>1;
    if(l==x&&y==r)return t[k].mx;
    if(y<=mid)return querymx(k<<1,x,y);
    else if(x>mid)return querymx(k<<1|1,x,y);
    else {return max(querymx(k<<1,x,mid),querymx(k<<1|1,mid+1,y));}
}
int solvesum(int x,int y)
{
	int sum=0;
    while(bl[x]!=bl[y])
    {
		if(dep[bl[x]]<dep[bl[y]])swap(x,y);
		sum+=querysum(1,pos[bl[x]],pos[x]);
		x=fa[bl[x]];
	}
	if(pos[x]>pos[y])swap(x,y);
	sum+=querysum(1,pos[x],pos[y]);
    return sum;
}
int solvemx(int x,int y)
{
	int mx=-inf;
    while(bl[x]!=bl[y])
    {
		if(dep[bl[x]]<dep[bl[y]])swap(x,y);
		mx=max(mx,querymx(1,pos[bl[x]],pos[x]));
		x=fa[bl[x]];
	}
	if(pos[x]>pos[y])swap(x,y);
	mx=max(mx,querymx(1,pos[x],pos[y]));
    return mx;
}
void solve()
{
    build(1,1,n);
    for(int i=1;i<=n;i++)
        change(1,pos[i],v[i]);
    scanf("%d",&q);
	char ch[10];
    for(int i=1;i<=q;i++) 
    {
        int x,y;scanf("%s%d%d",ch,&x,&y);
        if(ch[0]=='C'){v[x]=y;change(1,pos[x],y);}
        else
        {
            if(ch[1]=='M')
               printf("%d\n",solvemx(x,y));
            else
                printf("%d\n",solvesum(x,y));
        }
    }
}
int main()
{
    ini();
    dfs1(1);
    dfs2(1,1);
	solve();
    return 0;
}
4.bzoj4034树上操作(树链剖分)
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#define ll long long
#define N 200005
using namespace std;
int b[N],p[N],nt[N],fa[N],belong[N],cover[N],pos[N],v[N],sz[N];
ll sum[2*N],tag[2*N];
int n,m,cnt,num;
int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
void dfs(int x){
	sz[x]=1;
	for(int e=p[x];e;e=nt[e]){
		int k=b[e];
		if(k!=fa[x])
		{
			fa[k]=x;
			dfs(k);
			sz[x]+=sz[k];
			cover[x]=max(cover[x],cover[k]);//cover表示这个点的子树最大到多少 
		}
	}
}
void dfs2(int x,int idno){
	belong[x]=idno;
	num++;
	pos[x]=num;
	cover[x]=num;
	int k=0;
	for(int e=p[x];e;e=nt[e]){
		int kk=b[e];
		if(kk!=fa[x]&&sz[kk]>sz[k])
			k=kk;
	}
	if(k>0){
		dfs2(k,idno);//这条链的祖先都是第一个  不能写成dfs2(k,x) 不然就超时 
		cover[x]=max(cover[x],cover[k]);
	}
	for(int e=p[x];e;e=nt[e]){//轻边 
		int kk=b[e];
		if(kk!=k&&kk!=fa[x]){
			dfs2(kk,kk);
			cover[x]=max(cover[x],cover[kk]);
		}
	}
}
void pushdown(int l,int r,int k)
{
	if(l==r)return;
	int mid=(l+r)>>1;
	ll t=tag[k];
	tag[k]=0;
	tag[k<<1]+=t; tag[k<<1|1]+=t;
	sum[k<<1]+=t*(mid-l+1);
	sum[k<<1|1]+=t*(r-mid);
}
void add(int k,int l,int r,int x,int y,ll val){//改进版的线段树操作 
	if(tag[k]) pushdown(l,r,k);
	if(l==x&&y==r)	{tag[k]+=val;sum[k]+=(r-l+1)*val;return;}
	int mid=(l+r)>>1;
	if(x<=mid) add(k<<1,l,mid,x,min(mid,y),val);
	if(y>mid) add(k<<1|1,mid+1,r,max(mid+1,x),y,val);
	sum[k]=sum[k<<1]+sum[k<<1|1];
}
void insert(int x,int y){
	cnt++;b[cnt]=y;nt[cnt]=p[x];p[x]=cnt;
	cnt++;b[cnt]=x;nt[cnt]=p[y];p[y]=cnt;
}
ll query(int k,int l,int r,int x,int y){
	if(tag[k])pushdown(l,r,k);
	if(l==x&&y==r)return sum[k];
	int mid=(l+r)>>1;
	ll ans=0;
	if(x<=mid)
		ans+=query(k<<1,l,mid,x,min(mid,y));
	if(y>mid)
		ans+=query(k<<1|1,mid+1,r,max(mid+1,x),y);
	return ans;
}
ll querysum(int x){
	ll s=0;
	while(belong[x]!=1){
		s+=query(1,1,n,pos[belong[x]],pos[x]);
		x=fa[belong[x]];
	} 
	s+=query(1,1,n,1,pos[x]);
	return s;
}
int main(){
	n=read();m=read();
	for(int i=1;i<=n;i++) v[i]=read();
	for(int i=1;i<n;i++){
		int u,v;
		u=read(),v=read();
		insert(u,v);
	}
	dfs(1);
	dfs2(1,1);
	for(int i=1;i<=n;i++)
		add(1,1,n,pos[i],pos[i],v[i]);
	int t,x,a;
	while(m--){
		t=read();x=read();
		if(t==1){
			a=read(); add(1,1,n,pos[x],pos[x],a);
		}
		if(t==2){
			a=read(); add(1,1,n,pos[x],cover[x],a);
		}
		if(t==3) printf("%lld\n",querysum(x));
	}
	return 0;
}
5.bzoj2243染色
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#define inf 0x7fffffff
#define N 100001
using namespace std;
int n,m,q,cnt,sz;
int v[N],dep[N],size[N],head[N],fa[N][20];
int pos[N],belong[N];
struct data{
	int to,next;
}e[2*N];
struct seg{
	int l,r,lc,rc,s,tag;//lc表示左端的颜色 rc右端颜色 合并的时候要用到 s是颜色数 tag是这段的颜色(线段树中的lazy操作)和setv类似 
}t[4*N];
void insert(int u,int v)
{
    e[++cnt].to=v;e[cnt].next=head[u];head[u]=cnt;
    e[++cnt].to=u;e[cnt].next=head[v];head[v]=cnt;
}
void ini()//读入 
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
		scanf("%d",&v[i]);
	int x,y;
	for(int i=1;i<n;i++){
		scanf("%d%d",&x,&y);
		insert(x,y);
	}
}
void dfs1(int x) //树链剖分操作 两个dfs 
{
    size[x]=1;
    for(int i=1;i<=17;i++) {
    	if(dep[x]<(1<<i)) break;
    	fa[x][i]=fa[fa[x][i-1]][i-1];//求LCA 
	}
    for(int i=head[x];i;i=e[i].next)
    {
        if(e[i].to==fa[x][0]) continue;
        dep[e[i].to]=dep[x]+1;
        fa[e[i].to][0]=x;
        dfs1(e[i].to);
        size[x]+=size[e[i].to];
    }
}
void dfs2(int x,int chain)
{
    int k=0;sz++;
    pos[x]=sz;
	belong[x]=chain;
    for(int i=head[x];i;i=e[i].next)
        if(dep[e[i].to]>dep[x]&&size[e[i].to]>size[k])
            k=e[i].to;
    if(k==0)return;
    dfs2(k,chain);
    for(int i=head[x];i;i=e[i].next)
        if(dep[e[i].to]>dep[x]&&k!=e[i].to)
            dfs2(e[i].to,e[i].to);
}
//以上是树链剖分 

int lca(int x,int y){//求LCA 
	if(dep[x]<dep[y]) swap(x,y);
	int t=dep[x]-dep[y];
	for(int i=0;i<=17;i++)	if(t&(1<<i))x=fa[x][i];
	if(x==y) return x;
	for(int i=17;i>=0;i--) 
		if(fa[x][i]!=fa[y][i])
		{x=fa[x][i];y=fa[y][i];}
	return fa[x][0];
}



void build(int k,int l,int r)//线段树操作 
{
    t[k].l=l;t[k].r=r;t[k].s=1;t[k].tag=-1;
    if(l==r)return;
    int mid=(l+r)>>1;
    build(k<<1,l,mid);
    build(k<<1|1,mid+1,r);
}

void pushup(int k){//合并 
	t[k].lc=t[k<<1].lc;t[k].rc=t[k<<1|1].rc;
	if(t[k<<1].rc==t[k<<1|1].lc) t[k].s=t[k<<1].s+t[k<<1|1].s-1;//当左儿子的右颜色==右儿子的左颜色 答案-1 
	else t[k].s=t[k<<1].s+t[k<<1|1].s; 
} 
void pushdown(int k){//向下传tag 改变颜色  
	int tmp=t[k].tag;t[k].tag=-1;
	if(tmp==-1||t[k].l==t[k].r) return ;
	t[k<<1].s=t[k<<1|1].s=1;
    t[k<<1].tag=t[k<<1|1].tag=tmp;
    t[k<<1].lc=t[k<<1].rc=tmp;
    t[k<<1|1].lc=t[k<<1|1].rc=tmp;
}

void change(int k,int x,int y,int c)//线段树的区间更新操作 
{	
	pushdown(k);
	if(t[k].l==x&&t[k].r==y)
	{t[k].lc=t[k].rc=c;t[k].s=1;t[k].tag=c;return;}
   	int mid=(t[k].l+t[k].r)/2;
   	if(y<=mid) change(k<<1,x,y,c);
   	else if(x>mid) change(k<<1|1,x,y,c);
   	else {
   		change(k<<1,x,mid,c);
   		change(k<<1|1,mid+1,y,c);
	}
	pushup(k);
}
int ask(int k,int x,int y){//询问颜色操作 
	if(t[k].l==x&&t[k].r==y) return t[k].s;
	pushdown(k);
	int mid=(t[k].l+t[k].r)/2;
	if(y<=mid) return ask(k<<1,x,y);
	else if(x>mid) return ask(k<<1|1,x,y);
	else {
		int tmp=1;
		if(t[k<<1].rc!=t[k<<1|1].lc) tmp=0;
		return ask(k<<1,x,mid)+ask(k<<1|1,mid+1,y)-tmp;
	}
}  
//以上是线段树 
 
int getc(int k,int x){//找最单点颜色操作 后面有用 
    pushdown(k);
    int l=t[k].l,r=t[k].r;
    if(l==r)return t[k].lc;
    int mid=(l+r)>>1;
    if(x<=mid)return getc(k<<1,x);
    else return getc(k<<1|1,x);
}
int solvesum(int x,int f){//树链剖分操作 找段数 
	int sum=0;
	while(belong[x]!=belong[f])
	{
		sum+=ask(1,pos[belong[x]],pos[x]);
		if(getc(1,pos[belong[x]])==getc(1,pos[fa[belong[x]][0]]))sum--;//如果这个链最上面的点的颜色和要连接的重链的那个连接点的颜色相同 就要减去1  
		x=fa[belong[x]][0];
	}
	sum+=ask(1,pos[f],pos[x]);
	return sum;
}
int solvechange(int x,int f,int c){//改变颜色 
	while(belong[x]!=belong[f])
    {
        change(1,pos[belong[x]],pos[x],c);
        x=fa[belong[x]][0]; 
    }
    change(1,pos[f],pos[x],c);
} 
void solve()
{
    build(1,1,n);
    for(int i=1;i<=n;i++)
        change(1,pos[i],pos[i],v[i]);
    int a,b,c;
    for(int i=1;i<=m;i++){
    	char ch[10];
    	scanf("%s",ch);
    	if(ch[0]=='Q'){
    		scanf("%d%d",&a,&b);
    		int t=lca(a,b);
    		printf("%d\n",solvesum(a,t)+solvesum(b,t)-1);
		}
		else {
			scanf("%d%d%d",&a,&b,&c);
			int t=lca(a,b);
			solvechange(a,t,c);
			solvechange(b,t,c);
		}
	}
}
int main()
{
    ini();
    dfs1(1);
    dfs2(1,1);
	solve();
    return 0;
}
6.bzoj3531[Sdoi2014]旅行
此题是7题中最难的一个了 因为自己比较渣 这题没有自己写 而是看懂了别人代码 对于每个c建一棵树然后树剖 还有root记录每个树的根 总之对于我这个蒟蒻太难了 下面是来源网络的代码
#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#define N 100010
using namespace std;
char s[3];
int qx,n,m,te,sz,q,tot;
int num[N],size[N],tree[N],val[N],w[N],c[N];
int head[N],son[N],fa[N],h[N],tp[N],root[N];
struct edge{
    int v,next;
}e[200010];
struct seg{
    int sum,mx;
    int l,r,lch,rch;
}tr[2000010];
inline int F()
{
    register int aa,bb;register char ch;
    while(ch=getchar(),(ch<'0'||ch>'9')&&ch!='-');ch=='-'?aa=bb=0:(aa=ch-'0',bb=1);
    while(ch=getchar(),ch>='0'&&ch<='9')aa=(aa<<3)+(aa<<1)+ch-'0';return bb?aa:-aa;
}
void add(int u,int v)
{
    e[++te].v=v;
    e[te].next=head[u];
    head[u]=te;
}
void dfs1(int x)
{
    size[x]=1;
    for (int i=head[x];i;i=e[i].next)
    {
        int v=e[i].v;
        if (v==fa[x])continue;
        fa[v]=x;
        h[v]=h[x]+1;
        dfs1(v);
        size[x]+=size[v];
        if (size[v]>size[son[x]])son[x]=v;
    }
}
void dfs2(int x,int chain)
{
    tp[x]=chain;
    num[x]=++sz;
    if (!son[x])return;
    dfs2(son[x],chain);
    for (int i=head[x];i;i=e[i].next)
    {
        int v=e[i].v;
        if (v==fa[x]||v==son[x])continue;
        dfs2(v,v);
    }
}
void updata(int k)
{
    tr[k].sum=tr[tr[k].lch].sum+tr[tr[k].rch].sum;
    tr[k].mx=max(tr[tr[k].lch].mx,tr[tr[k].rch].mx);
}
void build(int &k,int l,int r,int x,int v)
{
    int mid=(l+r)>>1;
    if(!k)k=++tot;
    tr[k].l=l,tr[k].r=r;
    if (l==r)
    {
        tr[k].sum=v;
        tr[k].mx=v;
        return;
    }
    if (x<=mid)build(tr[k].lch,l,mid,x,v);
    else build(tr[k].rch,mid+1,r,x,v);
    updata(k); 
}
void querysum(int k,int x,int y)
{
    int l=tr[k].l,r=tr[k].r;
    if (!k)return;
    if (x<=l&&r<=y)
    {
        qx+=tr[k].sum;
        return;
    }
    int mid=(l+r)>>1;
    if (x<=mid)querysum(tr[k].lch,x,y);
    if (y>mid)querysum(tr[k].rch,x,y);
}
void querymax(int k,int x,int y)
{
    int l=tr[k].l,r=tr[k].r;
    if (!k)return;
    if (x<=l&&r<=y)
    {
        qx=max(qx,tr[k].mx);
        return;
    }
    int mid=(l+r)>>1;
    if (x<=mid)querymax(tr[k].lch,x,y);
    if (y>mid)querymax(tr[k].rch,x,y);
}
int solvesum(int x,int y,int st)
{
    qx=0;
    while(tp[x]!=tp[y])
    {
        if (h[tp[x]]<h[tp[y]])swap(x,y);
        querysum(root[st],num[tp[x]],num[x]);
        x=fa[tp[x]];
    }
    if (num[x]>num[y])swap(x,y);
    querysum(root[st],num[x],num[y]);
    return qx;
}
int solvemax(int x,int y,int st)
{
    qx=0;
    while(tp[x]!=tp[y])
    {
        if (h[tp[x]]<h[tp[y]])swap(x,y);
        querymax(root[st],num[tp[x]],num[x]);
        x=fa[tp[x]];
    }
    if (num[x]>num[y])swap(x,y);
    querymax(root[st],num[x],num[y]);
    return qx;
}
int main()
{
    int u,v,x,C,y;
    n=F(),q=F();
    for(int i=1;i<=n;++i)
    w[i]=F(),c[i]=F();
    for (int i=1;i<n;++i)
    u=F(),v=F(),add(u,v),add(v,u);
    h[1]=1;dfs1(1);dfs2(1,1);
    for (int i=1;i<=n;++i)
    build(root[c[i]],1,n,num[i],w[i]); 
    for (int i=1;i<=q;++i)
    {
        scanf("%s",s);x=F(),y=F();
        if (s[0]=='C'&&s[1]=='C')
        {
            build(root[c[x]],1,n,num[x],0);
            build(root[y],1,n,num[x],w[x]);
            c[x]=y;
        }
        else if (s[0]=='C'&&s[1]=='W')
        {
            build(root[c[x]],1,n,num[x],y);
            w[x]=y;
        }
        else if (s[0]=='Q'&&s[1]=='S')
        printf("%d\n",solvesum(x,y,c[x]));
        else if (s[0]=='Q'&&s[1]=='M')
        printf("%d\n",solvemax(x,y,c[x]));
    }
}

7.bzoj1984月下毛景树
此题放在最后一个 不是它难 而是我写这题的时候因为一个 if后面多打了一个分号(相当于没判)这一个小问题
调试了一个 下午两个多小时+晚自习+早上两个多小时 对拍了无数遍 还要了数据 qwq ╮(╯▽╰)╭ 所以放在最后一个 留作纪念
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#define N 100001
#define inf 0x7fffffff
using namespace std;
struct data{int to,v,next;}e[2*N];
struct node{int l,r,mx,a,c;}t[4*N];
int n,belong[N],size[N],dep[N],head[N],fa[N],pos[N],cnt,sz,id[N];
void insert(int u,int v,int w)
{
    cnt++;e[cnt].to=v;e[cnt].v=w;e[cnt].next=head[u];head[u]=cnt;
    cnt++;e[cnt].to=u;e[cnt].v=w;e[cnt].next=head[v];head[v]=cnt;
}
void ini()
{
   scanf("%d",&n);
   int x,y,z;
   for(int i=1;i<n;i++)
   {
   		scanf("%d%d%d",&x,&y,&z);
   		insert(x,y,z);
   }
}
int lca(int x,int y){
	while(belong[x]!=belong[y]){
		if(dep[belong[x]]<dep[belong[y]])swap(x,y);
		x=fa[belong[x]];
	}if(dep[x]>dep[y])swap(x,y);
	return x;
}
void build(int k,int l,int r)
{
    t[k].l=l;t[k].r=r;t[k].c=-1;
    if(l==r)return;
    int mid=(l+r)>>1;
    build(k<<1,l,mid);
    build(k<<1|1,mid+1,r);
}
void pushdown(int k){
	if(t[k].l==t[k].r) return ;
	if(t[k].c!=-1){
		t[k<<1].a=t[k<<1|1].a=0;
		t[k<<1].c=t[k<<1|1].c=t[k].c;
		t[k<<1].mx=t[k<<1|1].mx=t[k].c;
		t[k].c=-1;
	}
	if(t[k].a){
		t[k<<1].mx+=t[k].a;t[k<<1|1].mx+=t[k].a;
		if(t[k<<1].c!=-1) t[k<<1].c+=t[k].a;
		else  t[k<<1].a+=t[k].a;
		if(t[k<<1|1].c!=-1) t[k<<1|1].c+=t[k].a;
		else t[k<<1|1].a+=t[k].a;
		t[k].a=0;
	}
}
void pushup(int k){	t[k].mx=max(t[k<<1].mx,t[k<<1|1].mx);}
void change(int k,int x,int y,int v){
	
	if(x>y)return;
	if(t[k].l==x&&t[k].r==y){
		t[k].a=0;t[k].c=v;t[k].mx=v;return ;
	}
	int mid=(t[k].l+t[k].r)/2;pushdown(k);
	if(y<=mid) change(k<<1,x,y,v);
	else if(x>mid) change(k<<1|1,x,y,v);
	else {
		change(k<<1,x,mid,v);
		change(k<<1|1,mid+1,y,v);
	}
	pushup(k);
}
void add(int k,int x,int y,int v){
	
	if(x>y)return;
	if(t[k].l==x&&t[k].r==y){
		t[k].mx+=v;t[k].a+=v;return ;
	}pushdown(k);
	int mid=(t[k].l+t[k].r)/2;
	if(y<=mid) add(k<<1,x,y,v);
	else if(x>mid) add(k<<1|1,x,y,v);
	else {
		add(k<<1,x,mid,v);
		add(k<<1|1,mid+1,y,v);
	}
	pushup(k);
}
int ask(int k,int x,int y){
	if(x>y)return 0;
	if(t[k].l==x&&t[k].r==y)
	{return t[k].mx;}pushdown(k);
	int mid=(t[k].l+t[k].r)/2;
	if(y<=mid) return ask(k<<1,x,y);
	else if(x>mid) return ask(k<<1|1,x,y);
	else return max(ask(k<<1,x,mid),ask(k<<1|1,mid+1,y));
}
void dfs1(int x,int f)
{
    size[x]=1;
    for(int i=head[x];i;i=e[i].next)
    {
        if(e[i].to==f)continue;
        dep[e[i].to]=dep[x]+1;
        fa[e[i].to]=x;
        dfs1(e[i].to,x);
        size[x]+=size[e[i].to];
    }
}
int tree[N];
void dfs2(int x,int chain)
{
    int k=0;
    pos[x]=++sz;tree[sz]=x;
	belong[x]=chain;
    for(int i=head[x];i;i=e[i].next)
    {
		if(dep[e[i].to]>dep[x])
		{
			if(size[e[i].to]>size[k])
			k=e[i].to;
		}
		else {
			id[(i+1)>>1]=x;
			add(1,pos[x],pos[x],e[i].v);
		}
	}
    if(k==0)return;
    dfs2(k,chain);
    for(int i=head[x];i;i=e[i].next)
        if(dep[e[i].to]>dep[x]&&k!=e[i].to)
            dfs2(e[i].to,e[i].to);
}
void solvechange(int x,int f,int v)
{
	while(belong[x]!=belong[f])
	{
		change(1,pos[belong[x]],pos[x],v);
		x=fa[belong[x]];
	}
	if(pos[f]<pos[x])
	change(1,pos[f]+1,pos[x],v);
}
void solveadd(int x,int f,int v){
	while(belong[x]!=belong[f]){
		add(1,pos[belong[x]],pos[x],v);
		x=fa[belong[x]];
	}
	if(pos[f]<pos[x])
	add(1,pos[f]+1,pos[x],v);
}
int solveask(int x,int f){
	int mx=-inf;
	while(belong[x]!=belong[f]){
		mx=max(mx,ask(1,pos[belong[x]],pos[x]));
		x=fa[belong[x]];
	}
	if(pos[f]<pos[x])
		mx=max(mx,ask(1,pos[f]+1,pos[x]));
	return mx;
}
FILE *fout;
void solve(){
	char s[10];
	int u,v,w,f,cnt=0;
	while(1)
	{
		scanf("%s",s);
		cnt++;printf("%d ",cnt);
		switch(s[1])
		{
			case 't':	return;break;

			case 'd':	scanf("%d%d%d",&u,&v,&w);
						f=lca(u,v);
			         	solveadd(u,f,w);solveadd(v,f,w);break;

			case 'o':	scanf("%d%d%d",&u,&v,&w);
						f=lca(u,v);
				     	solvechange(u,f,w);solvechange(v,f,w);break;

			case 'h':	scanf("%d%d",&u,&w);
						change(1,pos[id[u]],pos[id[u]],w);break;

			case 'a':	scanf("%d%d",&u,&v);
					 	f=lca(u,v);
			        	fprintf(fout,"%d\n",max(solveask(u,f),solveask(v,f)));break;
		}
	}
}
int main(){
	freopen("D:\\1984\\data\\1984\\msn1.in","r",stdin);
	freopen("out.txt","w",stdout);
	//fout=fopen("out.txt","w");
	ini();
	build(1,1,n);
	dfs1(1,0);
	dfs2(1,1);
	//for(int i=1;i<=n;i++)printf("%d\n",size[i]);
	solve();
	return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
#include <cstdio> #include <iostream> #include <vector> #define N 30003 #define INF 2147483647 using namespace std; int n,f[N][20],dep[N],siz[N],son[N],top[N],tot,pos[N],w[N]; int Max[N*4],Sum[N*4]; vector <int> to[N]; void dfs1(int x){ siz[x]=1; int sz=to[x].size(); for(int i=0;i<sz;++i){ int y=to[x][i]; if(y==f[x][0])continue; f[y][0]=x; dep[y]=dep[x]+1; dfs1(y); siz[x]+=siz[y]; if(siz[y]>siz[son[x]])son[x]=y; } } void dfs2(int x,int root){ top[x]=root; pos[x]=++tot; if(son[x])dfs2(son[x],root); int sz=to[x].size(); for(int i=0;i<sz;++i){ int y=to[x][i]; if(y==f[x][0] || y==son[x])continue; dfs2(y,y); } } void update(int k,int l,int r,int P,int V){ if(l==r){ Max[k]=Sum[k]=V; return; } int mid=(l+r)>>1; if(P<=mid)update(k*2,l,mid,P,V); else update(k*2+1,mid+1,r,P,V); Max[k]=max(Max[k*2],Max[k*2+1]); Sum[k]=Sum[k*2]+Sum[k*2+1]; } void up(int &x,int goal){ for(int i=15;i>=0;--i) if(dep[f[x][i]]>=goal)x=f[x][i]; } int lca(int x,int y){ if(dep[x]>dep[y])up(x,dep[y]); if(dep[x]<dep[y])up(y,dep[x]); if(x==y)return x; for(int i=15;i>=0;--i) if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i]; return f[x][0]; } int getm(int k,int l,int r,int L,int R){ if(L<=l && r<=R)return Max[k]; int res=-INF,mid=(l+r)>>1; if(L<=mid)res=max(res,getm(k*2,l,mid,L,R)); if(R>mid)res=max(res,getm(k*2+1,mid+1,r,L,R)); return res; } int gets(int k,int l,int r,int L,int R){ if(L<=l && r<=R)return Sum[k]; int res=0,mid=(l+r)>>1; if(L<=mid)res+=gets(k*2,l,mid,L,R); if(R>mid)res+=gets(k*2+1,mid+1,r,L,R); return res; } int main(){ scanf("%d",&n); for(int i=1,a,b;i<n;++i){ scanf("%d%d",&a,&b); to[a].push_back(b); to[b].push_back(a); } dep[1]=1; dfs1(1); dfs2(1,1); for(int i=1;i<=15;++i) for(int j=1;j<=n;++j)f[j][i]=f[f[j][i-1]][i-1]; for(int i=1;i<=n;++i){ scanf("%d",&w[i]); update(1,1,n,pos[i],w[i]); } int q; scanf("%d",&q); while(q--){ char s[10]; int u,v,t; scanf("%s",s); if(s[1]=='H'){ scanf("%d%d",&u,&t); w[u]=t; update(1,1,n,pos[u],t); } if(s[1]=='M'){ scanf("%d%d",&u,&v); int ans=-INF,t=lca(u,v); for(int i=u;i;i=f[top[i]][0]) if(dep[t]<dep[top[i]]) ans=max(ans,getm(1,1,n,pos[top[i]],pos[i])); else{ ans=max(ans,getm(1,1,n,pos[t],pos[i])); break; } for(int i=v;i;i=f[top[i]][0]) if(dep[t]<dep[top[i]]) ans=max(ans,getm(1,1,n,pos[top[i]],pos[i])); else{ ans=max(ans,getm(1,1,n,pos[t],pos[i])); break; } printf("%d\n",ans); } if(s[1]=='S'){ scanf("%d%d",&u,&v); int ans=0,t=lca(u,v); for(int i=u;i;i=f[top[i]][0]) if(dep[t]<dep[top[i]]) ans+=gets(1,1,n,pos[top[i]],pos[i]); else{ ans+=gets(1,1,n,pos[t],pos[i]); break; } for(int i=v;i;i=f[top[i]][0]) if(dep[t]<dep[top[i]]) ans+=gets(1,1,n,pos[top[i]],pos[i]); else{ ans+=gets(1,1,n,pos[t],pos[i]); break; } printf("%d\n",ans-w[t]); } } }

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值