zoukankan      html  css  js  c++  java
  • BZOJ4817: [Sdoi2017]树点涂色

    4817: [Sdoi2017]树点涂色

    Time Limit: 10 Sec  Memory Limit: 128 MB
    Submit: 515  Solved: 302
    [Submit][Status][Discuss]

    Description

    Bob有一棵n个点的有根树,其中1号点是根节点。Bob在每个点上涂了颜色,并且每个点上的颜色不同。定义一条路
    径的权值是:这条路径上的点(包括起点和终点)共有多少种不同的颜色。Bob可能会进行这几种操作:
    1 x:
    把点x到根节点的路径上所有的点染上一种没有用过的新颜色。
    2 x y:
    求x到y的路径的权值。
    3 x y:
    在以x为根的子树中选择一个点,使得这个点到根节点的路径权值最大,求最大权值。
    Bob一共会进行m次操作

    Input

    第一行两个数n,m。
    接下来n-1行,每行两个数a,b,表示a与b之间有一条边。
    接下来m行,表示操作,格式见题目描述
    1<=n,m<=100000

    Output

    每当出现2,3操作,输出一行。
    如果是2操作,输出一个数表示路径的权值
    如果是3操作,输出一个数表示权值的最大值

    Sample Input

    5 6
    1 2
    2 3
    3 4
    3 5
    2 4 5
    3 3
    1 4
    2 4 5
    1 5
    2 4 5

    Sample Output

    3
    4
    2
    2
     
    思路{
      双倍经验题,同BZOJ3779
      具体来说的话查询路径间的权值就是拿$Ans_x+Ans_y-2*Ans_{lca}+1$。
      线段树大力搞一下就可以了。
    }
    #include<bits/stdc++.h>
    #define LL long long
    #define RG register
    #define il inline
    #define N 100010
    using namespace std;
    namespace tree{
    #define rs ((o<<1)|1)
    #define ls (o<<1)
    #define mid ((l+r)>>1)
        int Max[N*4],lazy[N*4];
        void down(int o){
    	if(lazy[o]){
    	    lazy[rs]+=lazy[o],lazy[ls]+=lazy[o];
    	    Max[rs]+=lazy[o],Max[ls]+=lazy[o];
    	    lazy[o]=0;
    	}
        }
        void modify(int o,int l,int r,int L,int R,int num){
    	if(l>=L&&r<=R){Max[o]+=num,lazy[o]+=num;return;}
    	down(o);
    	if(mid<L)modify(rs,mid+1,r,L,R,num);
    	else if(mid>=R)modify(ls,l,mid,L,R,num);
    	else modify(rs,mid+1,r,l,R,num),modify(ls,l,mid,L,R,num);
    	Max[o]=max(Max[rs],Max[ls]);
        }
        int query(int o,int l,int r,int L,int R){
    	if(l>=L&&r<=R)return Max[o];
    	down(o);
    	if(mid<L)return query(rs,mid+1,r,L,R);
    	else if(mid>=R)return query(ls,l,mid,L,R);
    	else return max(query(rs,mid+1,r,L,R),query(ls,l,mid,L,R));
        }
    }
    struct ed{int nxt,to;}e[N*2];
    int f[19][N],head[N],tot,dfn[N],til[N],id,n,q,fa[N],ch[N][2],dep[N],st[N];
    void link(int u,int v){e[tot].nxt=head[u];e[tot].to=v;head[u]=tot++;}
    void dfs(int u,int faa){fa[u]=faa;
        dep[u]=dep[faa]+1;dfn[u]=++id;tree::modify(1,1,n,dfn[u],dfn[u],dep[u]);
        f[0][u]=faa;for(int i=1;i<=18;++i)f[i][u]=f[i-1][f[i-1][u]];
        for(int i=head[u];i!=-1;i=e[i].nxt){
    	int v=e[i].to;if(v==faa)continue;
    	dfs(v,u);
        }til[u]=id;
    }
    int lca(int x,int y){
        if(dep[x]<dep[y])swap(x,y);int de=dep[x]-dep[y];
        for(int i=0;i<=18;++i)if((1<<i)&de)x=f[i][x];
        if(x!=y){
    	for(int i=18;i!=-1;i--)if(f[i][x]!=f[i][y])x=f[i][x],y=f[i][y];
    	x=f[0][x];
        }return x;
    }
    bool isroot(int x){return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;}
    void Rotate(int x){
        int y=fa[x],z=fa[y];
        int l=(ch[y][1]==x),r=l^1;
        if(!isroot(y))ch[z][ch[z][1]==y]=x;
        ch[y][l]=ch[x][r];fa[ch[x][r]]=y;
        ch[x][r]=y;fa[x]=z,fa[y]=x;
    }
    void Splay(int x){
        int y(x),z;
        while(!isroot(x)){
    	y=fa[x],z=fa[y];
    	if(!isroot(y)){
    	    if(ch[z][0]==y^ch[y][0]==x)Rotate(x);
    	    else Rotate(y);
    	}Rotate(x);
        }
    }
    int find(int x){
        while(ch[x][0])x=ch[x][0];
        return x;
    }
    void access(int x){
        int t(0);
        while(x){
    	Splay(x);
    	if(t){
    	    int u=find(t);
    	    tree::modify(1,1,n,dfn[u],til[u],-1);
    	}
    	if(ch[x][1]){
    	    int u=find(ch[x][1]);
    	    tree::modify(1,1,n,dfn[u],til[u],1);
    	}
    	ch[x][1]=t,t=x,x=fa[x];
        }
    }
    int main(){
      freopen("1.in","r",stdin);
      freopen("1.out","w",stdout);
      memset(head,-1,sizeof(head));
      scanf("%d%d",&n,&q);
      for(int i=1;i<n;++i){int u,v;scanf("%d%d",&u,&v),link(u,v),link(v,u);}
      dfs(1,1);int flag,x,y;fa[1]=0;
      using namespace tree;
      for(int i=1;i<=q;++i){
          scanf("%d%d",&flag,&x);
          if(flag==1)access(x);
          if(flag==2){
    	  scanf("%d",&y);int Lca=lca(x,y);
    	  printf("%d
    ",query(1,1,n,dfn[x],dfn[x])+query(1,1,n,dfn[y],dfn[y])-
    		 2*query(1,1,n,dfn[Lca],dfn[Lca])+1);
          }
          if(flag==3)printf("%d
    ",query(1,1,n,dfn[x],til[x]));
      }return 0;
    }
    
  • 相关阅读:
    ASP输出成n列的表格形式显示的方法,多行多列
    1003
    1005
    Linq to sql 迭代器bug?
    通过global.asax向所有文件注册js
    asp.net任务调度之Quartz.net
    SQL Server 批量插入数据的两种方法
    C#通过反射实例化对象
    linq to sql 学习
    C#全角和半角转换
  • 原文地址:https://www.cnblogs.com/zzmmm/p/7838380.html
Copyright © 2011-2022 走看看