zoukankan      html  css  js  c++  java
  • 【BZOJ3589】动态树 树链剖分+线段树

    【BZOJ3589】动态树

    Description

    别忘了这是一棵动态树, 每时每刻都是动态的. 小明要求你在这棵树上维护两种事件
    事件0:
    这棵树长出了一些果子, 即某个子树中的每个节点都会长出K个果子.
    事件1:
    小明希望你求出几条树枝上的果子数. 一条树枝其实就是一个从某个节点到根的路径的一段. 每次小明会选定一些树枝, 让你求出在这些树枝上的节点的果子数的和. 注意, 树枝之间可能会重合, 这时重合的部分的节点的果子只要算一次.

    Input

    第一行一个整数n(1<=n<=200,000), 即节点数.
    接下来n-1行, 每行两个数字u, v. 表示果子u和果子v之间有一条直接的边. 节点从1开始编号.
    在接下来一个整数nQ(1<=nQ<=200,000), 表示事件.
    最后nQ行, 每行开头要么是0, 要么是1.
    如果是0, 表示这个事件是事件0. 这行接下来的2个整数u, delta表示以u为根的子树中的每个节点长出了delta个果子.
    如果是1, 表示这个事件是事件1. 这行接下来一个整数K(1<=K<=5), 表示这次询问涉及K个树枝. 接下来K对整数u_k, v_k, 每个树枝从节点u_k到节点v_k. 由于果子数可能非常多, 请输出这个数模2^31的结果.

    Output

    对于每个事件1, 输出询问的果子数.

    Sample Input

    5
    1 2
    2 3
    2 4
    1 5
    3
    0 1 1
    0 2 3
    1 2 3 1 1 4

    Sample Output

    13

    HINT

     1 <= n <= 200,000, 1 <= nQ <= 200,000, K = 5.

    生成每个树枝的过程是这样的:先在树中随机找一个节点, 然后在这个节点到根的路径上随机选一个节点, 这两个节点就作为树枝的两端.

    题解:话说这题做法好多啊,容斥、打标记、黑科技。。。是数据比较良心的缘故?

    我的做法也类似于黑科技吧?因为我们在查询时,会访问到线段树上许多个可能会重叠的区间,那么我给线段树的每个节点都增加一个时间标记。当我们在线段树找到一个合法的整区间后,还要继续判断这个区间的在当前的时间是否打过标记,然后继续向下查找。这样做的时间复杂度我也不太清楚,大概O(nlog3n)差不多吧?

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #define lson x<<1
    #define rson x<<1|1
    using namespace std;
    const int maxn=200010;
    int n,m,cnt,now,ans;
    int to[maxn<<1],next[maxn<<1],head[maxn],v[maxn],fa[maxn],dep[maxn],siz[maxn],son[maxn],top[maxn];
    int tt[maxn<<2],ts[maxn<<2],s[maxn<<2],tm[maxn<<2],tn[maxn<<2],p[maxn],q[maxn];
    void add(int a,int b)
    {
    	to[cnt]=b,next[cnt]=head[a],head[a]=cnt++;
    }
    void dfs1(int x)
    {
    	siz[x]=1;
    	for(int i=head[x];i!=-1;i=next[i])
    	{
    		if(to[i]!=fa[x])
    		{
    			fa[to[i]]=x,dep[to[i]]=dep[x]+1,dfs1(to[i]),siz[x]+=siz[to[i]];
    			if(siz[to[i]]>siz[son[x]])	son[x]=to[i];
    		}
    	}
    }
    void dfs2(int x,int tp)
    {
    	top[x]=tp,p[x]=++p[0];
    	if(son[x])	dfs2(son[x],tp);
    	for(int i=head[x];i!=-1;i=next[i])
    		if(to[i]!=fa[x]&&to[i]!=son[x])
    			dfs2(to[i],to[i]);
    	q[x]=p[0];
    }
    void pushdown(int l,int r,int x)
    {
    	if(tt[x])	tt[lson]=tt[rson]=tm[lson]=tm[rson]=tn[lson]=tn[rson]=tt[x],tt[x]=0;
    	if(ts[x])
    	{
    		int mid=l+r>>1;
    		ts[lson]+=ts[x],ts[rson]+=ts[x],s[lson]+=(mid-l+1)*ts[x],s[rson]+=(r-mid)*ts[x],ts[x]=0;
    	}
    }
    void pushup(int x)
    {
    	tm[x]=max(tm[lson],tm[rson]);
    	tn[x]=min(tn[lson],tn[rson]);
    	s[x]=s[lson]+s[rson];
    }
    void updata(int l,int r,int x,int a,int b,int c)
    {
    	if(a<=l&&r<=b)
    	{
    		s[x]+=(r-l+1)*c,ts[x]+=c;
    		return ;
    	}
    	pushdown(l,r,x);
    	int mid=l+r>>1;
    	if(a<=mid)	updata(l,mid,lson,a,b,c);
    	if(b>mid)	updata(mid+1,r,rson,a,b,c);
    	pushup(x);
    }
    void q2(int l,int r,int x)
    {
    	if(tm[x]<now)
    	{
    		ans+=s[x],tm[x]=tn[x]=tt[x]=now;
    		return ;
    	}
    	pushdown(l,r,x);
    	int mid=l+r>>1;
    	if(tn[lson]<now)	q2(l,mid,lson);
    	if(tn[rson]<now)	q2(mid+1,r,rson);
    	pushup(x);
    }
    void q1(int l,int r,int x,int a,int b)
    {
    	if(a<=l&&r<=b)
    	{
    		if(tn[x]<now)	q2(l,r,x);
    		return ;
    	}
    	pushdown(l,r,x);
    	int mid=l+r>>1;
    	if(a<=mid)	q1(l,mid,lson,a,b);
    	if(b>mid)	q1(mid+1,r,rson,a,b);
    	pushup(x);
    }
    void ask(int x,int y)
    {
    	if(dep[x]<dep[y])	swap(x,y);
    	while(top[x]!=top[y])
    	{
    		q1(1,n,1,p[top[x]],p[x]);
    		x=fa[top[x]];
    	}
    	q1(1,n,1,p[y],p[x]);
    }
    int rd()
    {
    	int ret=0,f=1;	char gc=getchar();
    	while(gc<'0'||gc>'9')	{if(gc=='-')f=-f;	gc=getchar();}
    	while(gc>='0'&&gc<='9')	ret=ret*10+gc-'0',gc=getchar();
    	return ret*f;
    }
    int main()
    {
    	n=rd();
    	int i,j,a,b,c;
    	memset(head,-1,sizeof(head));
    	for(i=1;i<n;i++)	a=rd(),b=rd(),add(a,b),add(b,a);
    	dep[1]=1,dfs1(1),dfs2(1,1);
    	m=rd();
    	for(i=1;i<=m;i++)
    	{
    		if(!rd())	a=rd(),updata(1,n,1,p[a],q[a],rd());
    		else
    		{
    			c=rd(),now++,ans=0;
    			for(j=1;j<=c;j++)	a=rd(),b=rd(),ask(a,b);
    			printf("%d
    ",ans&2147483647);
    		}
    	}
    	return 0;
    }
  • 相关阅读:
    DDL、DML、TCL
    SQL简介
    Java基础--常用API--IO流相关API
    Java基础--多线程
    Java基础--常用API--集合类相关API
    Java基础--常用API--日期相关API
    Java基础--常用API--字符串相关API
    Java基础--正则表达式的规则
    Java基础--常用API--java.lang.Object
    26、springboot——整合JPA
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/7088071.html
Copyright © 2011-2022 走看看