【BZOJ1984】月下“毛景树”-树链剖分

Description

  毛毛虫经过及时的变形,最终逃过的一劫,离开了菜妈的菜园。 毛毛虫经过千山万水,历尽千辛万苦,最后来到了小小的绍兴一中的校园里。爬啊爬爬啊爬毛毛虫爬到了一颗小小的“毛景树”下面,发现树上长着他最爱吃的毛毛果~~ “毛景树”上有N个节点和N-1条树枝,但节点上是没有毛毛果的,毛毛果都是长在树枝上的。但是这棵“毛景树”有着神奇的魔力,他能改变树枝上毛毛果的个数:
  Change k w:将第k条树枝上毛毛果的个数改变为w个。
  Cover u v w:将节点u与节点v之间的树枝上毛毛果的个数都改变为w个。
  Add u v w:将节点u与节点v之间的树枝上毛毛果的个数都增加w个。
  由于毛毛虫很贪,于是他会有如下询问:
  Max u v:询问节点u与节点v之间树枝上毛毛果个数最多有多少个。

Input

  第一行一个正整数N。
  接下来N-1行,每行三个正整数Ui,Vi和Wi,第i+1行描述第i条树枝。表示第i条树枝连接节点Ui和节点Vi,树枝上有Wi个毛毛果。
  接下来是操作和询问,以“Stop”结束。

Output

  对于毛毛虫的每个询问操作,输出一个答案。

Sample Input

4
1 2 8
1 3 7
3 4 9
Max 2 4
Cover 2 4 5
Add 1 4 10
Change 1 16
Max 2 4
Stop

Sample Output

9
16

Hint

  1<=N<=100,000,操作+询问数目不超过100,000。
  保证在任意时刻,所有树枝上毛毛果的个数都不会超过10^9个。


思路

  • 树剖题,要注意标记,先执行cover标记,若无覆盖再执行add
  • 赋值-1的原因:果子个数为正
  • 改大半天后发现错误原因是x<<1写成了x<1 吐血三升
  • 文末再附一个洛谷剽来的数据生成器 方便调试

代码

#include <iostream>
#include <cstdio>
#include <cstring>
#define maxn 100005
using namespace std;
struct fdfdfd{int l,r,maxx,a,c;}a[maxn<<2];
struct node{int next,to,w;}e[maxn];
struct keeppp{int x,y,w;}q[maxn];
int n,cnt,head[maxn];
int deep[maxn],fa[maxn],son[maxn],siz[maxn],top[maxn],num[maxn],fnum[maxn];
void addedge(int x,int y,int w){e[++cnt].to=y; e[cnt].w=w; e[cnt].next=head[x]; head[x]=cnt;}
void dfs_1(int u,int pre)
{
	deep[u]=deep[pre]+1; fa[u]=pre; siz[u]=1;
	for(int i=head[u];i;i=e[i].next)
	{
		int v=e[i].to;
		if(v!=pre)
		{
			dfs_1(v,u); siz[u]+=siz[v];
			if(son[u]==-1||siz[v]>siz[son[u]]) son[u]=v;
		}
	}
}
void dfs_2(int u,int topp)
{
	top[u]=topp; num[u]=++cnt; fnum[cnt]=u;
	if(son[u]!=-1) dfs_2(son[u],topp);
	for(int i=head[u];i;i=e[i].next)
	{
		int v=e[i].to;
		if(v!=fa[u]&&v!=son[u]) dfs_2(v,v);
	}
}
void pushup(int x) {a[x].maxx=max(a[x<<1].maxx,a[x<<1|1].maxx);}
void pushdown(int x)
{
	if(a[x].c!=-1)
	{
		a[x<<1].c=a[x<<1|1].c=a[x].c;
		a[x<<1].maxx=a[x<<1|1].maxx=a[x].c;
		a[x<<1].a=a[x<<1|1].a=0;
		a[x].c=-1;
	}
	if(a[x].a!=0)
	{
		a[x<<1].maxx+=a[x].a; a[x<<1|1].maxx+=a[x].a;
		a[x<<1].a+=a[x].a; a[x<<1|1].a+=a[x].a;
		a[x].a=0;
	}
}
void build(int x,int left,int right)
{
	a[x].l=left; a[x].r=right; a[x].c=-1;
	if(left==right) return;
	int mid=(left+right)>>1;
	build(x<<1,left,mid); build(x<<1|1,mid+1,right);
}
void insert(int x,int v,int d)
{
	if(a[x].r<v||a[x].l>v) return;
	if(a[x].r==v&&a[x].l==v) {a[x].maxx=a[x].c=d; a[x].a=0; return;}
	pushdown(x);
	insert(x<<1,v,d); insert(x<<1|1,v,d);
	pushup(x);
}
void change_add(int x,int left,int right,int d)
{
	if(a[x].r<left||a[x].l>right) return;
	if(left<=a[x].l&&right>=a[x].r)
	{
		a[x].maxx+=d; a[x].a+=d;
		return;
	}
	pushdown(x);
	change_add(x<<1,left,right,d); change_add(x<<1|1,left,right,d);
	pushup(x);
}
void change_cover(int x,int left,int right,int d)
{
	if(a[x].r<left||a[x].l>right) return;
	if(left<=a[x].l&&right>=a[x].r)
	{
		a[x].maxx=d; a[x].c=d; a[x].a=0;
		return;
	}
	pushdown(x);
	change_cover(x<<1,left,right,d); change_cover(x<<1|1,left,right,d);
	pushup(x);
}
void modify_add(int u,int v,int d)
{
	while(top[u]!=top[v])
	{
		if(deep[top[u]]<deep[top[v]]) swap(u,v);
		change_add(1,num[top[u]],num[u],d);
		u=fa[top[u]];
	}
	if(u==v) return;
	if(deep[u]>deep[v]) swap(u,v);
	change_add(1,num[son[u]],num[v],d);
}
void modify_cover(int u,int v,int d)
{
	while(top[u]!=top[v])
	{
		if(deep[top[u]]<deep[top[v]]) swap(u,v);
		change_cover(1,num[top[u]],num[u],d);
		u=fa[top[u]];
	}
	if(u==v) return;
	if(deep[u]>deep[v]) swap(u,v);
	change_cover(1,num[son[u]],num[v],d);
}
int query(int x,int left,int right)
{
	if(a[x].r<left||a[x].l>right) return -1;
	if(left<=a[x].l&&right>=a[x].r) return a[x].maxx;
	pushdown(x);
	return max(query(x<<1,left,right),query(x<<1|1,left,right));
}
int askmax(int u,int v)
{
	int maxx=0;
	while(top[u]!=top[v])
	{
		if(deep[top[u]]<deep[top[v]]) swap(u,v);
		maxx=max(maxx,query(1,num[top[u]],num[u]));
		u=fa[top[u]];
	}
	if(u==v) return maxx;
	if(deep[u]>deep[v]) swap(u,v);
	maxx=max(maxx,query(1,num[son[u]],num[v]));
	return maxx;
}
int main()
{
	memset(son,-1,sizeof(son));
	scanf("%d",&n);
	for(int i=1;i<n;++i)
		scanf("%d%d%d",&q[i].x,&q[i].y,&q[i].w),addedge(q[i].x,q[i].y,q[i].w),addedge(q[i].y,q[i].x,q[i].w);
	dfs_1(1,0); cnt=0; dfs_2(1,1); build(1,1,n);
	for(int i=1;i<n;++i)
	{
		if(deep[q[i].x]<deep[q[i].y]) swap(q[i].x,q[i].y);
		insert(1,num[q[i].x],q[i].w);
	}
	char op[8]; int u,v,w;
	while(scanf("%s",&op))
	{
		if(op[0]=='S') break;
		if(op[0]=='C'&&op[1]=='h') scanf("%d%d",&u,&w),insert(1,num[q[u].x],w);
		else if(op[0]=='C'&&op[1]=='o') scanf("%d%d%d",&u,&v,&w),modify_cover(u,v,w);
		else if(op[0]=='A') scanf("%d%d%d",&u,&v,&w),modify_add(u,v,w);
		else scanf("%d%d",&u,&v),printf("%d\n",askmax(u,v));
	}
/*	Change k w:将第k条树枝上毛毛果的个数改变为w个。
  Cover u v w:将节点u与节点v之间的树枝上毛毛果的个数都改变为w个。
  Add u v w:将节点u与节点v之间的树枝上毛毛果的个数都增加w个。
  Max u v:询问节点u与节点v之间树枝上毛毛果个数最多有多少个。*/
	return 0;
}

附:(数据生成器)

广告一发对拍器

#include <bits/stdc++.h>
using namespace std;
int fa[100005],f[100005];
int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
int main()
{
    srand(time(0));
    int T=1;
//  cout<<T<<endl;
    while(T--)
    {
        memset(f,0,sizeof(f));
        int n=10;
        for(int i=1;i<=n;i++)fa[i]=i;
        int root=rand()%n+1;
        cout<<n<<endl; 
        for(int i=1;i<=n;i++)
        {
            if(i==root)continue;
            int father;
            do{father=rand()%n+1;}while(find(i)==find(father));
            f[i]=father;
            fa[find(i)]=find(father);
        }
        for(int i=1;i<=n;i++)
        {
            if(root==i)continue;
            cout<<i<<" "<<f[i]<<" "<<rand()%10<<endl;
        }
        int m=20;
        while(m--)
        {
            int opt=rand()%4;
            string s;
            switch(opt)
            {
                case 0:s="Change";break;
                case 1:s="Cover";break;
                case 2:s="Add";break;
                case 3:s="Max";break;
            }
            cout<<s<<" ";
            if(opt==0) cout<<rand()%(n-1)+1<<" "<<rand()%100<<endl;
            else if(opt==1) cout<<rand()%n+1<<" "<<rand()%n+1<<" "<<rand()%100<<endl;
            else if(opt==2) cout<<rand()%n+1<<" "<<rand()%n+1<<" "<<rand()%100<<endl;
            else cout<<rand()%n+1<<" "<<rand()%n+1<<endl;
        }
        cout<<"Stop"<<endl;
    }
}
posted @ 2020-08-10 17:15  wuwendongxi  阅读(169)  评论(0编辑  收藏  举报