• 【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
    ",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;
        }
    }
    
  • 相关阅读:
    开课博客
    高级UI组件(二)
    《梦断代码》读后感(三)
    高级UI组件
    今日总结
    今日总结
    android中关于时间的控件
    单选按钮和复选框
    Android开发中按钮的语法
    布局管理器的嵌套
  • 原文地址:https://www.cnblogs.com/wuwendongxi/p/13470900.html
Copyright © 2020-2023  润新知