zoukankan      html  css  js  c++  java
  • 【BZOJ3307】雨天的尾巴 线段树合并

    【BZOJ3307】雨天的尾巴

    Description

    N个点,形成一个树状结构。有M次发放,每次选择两个点x,y对于x到y的路径上(含x,y)每个点发一袋Z类型的物品。完成所有发放后,每个点存放最多的是哪种物品。

    Input

    第一行数字N,M
    接下来N-1行,每行两个数字a,b,表示a与b间有一条边
    再接下来M行,每行三个数字x,y,z.如题

    Output

    输出有N行
    每i行的数字表示第i个点存放最多的物品是哪一种,如果有多种物品的数量一样,输出编号最小的。如果某个点没有物品则输出0

    题解:看到题直接的想法就是树套树,但是由于可以离线,我们可以直接差分。

    具体地,我们对于每个点都维护一棵权值线段树,然后将标记差分,最后将每个节点的线段树与父亲节点的线段树合并即可。

    建议:在一开始的时候就为每个点创建一个rt节点。

    #include <cstdio>
    #include <iostream>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    const int maxn=100010;
    int inf=1000000000;
    int n,m,cnt,tot;
    int to[maxn<<1],next[maxn<<1],head[maxn],fa[19][maxn],dep[maxn],rt[maxn],p[maxn],ref[maxn];
    int v[maxn*50],s[maxn*50],ls[maxn*50],rs[maxn*50];
    struct node
    {
    	int a,b,c;
    }q[maxn];
    bool cmp(node a,node b)
    {
    	return a.c<b.c;
    }
    int rd()
    {
    	int ret=0;	char gc=getchar();
    	while(gc<'0'||gc>'9')	gc=getchar();
    	while(gc>='0'&&gc<='9')	ret=ret*10+gc-'0',gc=getchar();
    	return ret;
    }
    void add(int a,int b)
    {
    	to[++cnt]=b,next[cnt]=head[a],head[a]=cnt;
    }
    void dfs(int x)
    {
    	p[++p[0]]=x;
    	for(int i=head[x];i;i=next[i])
    		if(to[i]!=fa[0][x])	fa[0][to[i]]=x,dep[to[i]]=dep[x]+1,dfs(to[i]);
    }
    int lca(int a,int b)
    {
    	if(dep[a]<dep[b])	swap(a,b);
    	for(int i=18;i>=0;i--)	if(dep[fa[i][a]]>=dep[b])	a=fa[i][a];
    	if(a==b)	return a;
    	for(int i=18;i>=0;i--)	if(fa[i][a]!=fa[i][b])	a=fa[i][a],b=fa[i][b];
    	return fa[0][a];
    }
    void pushup(int x)
    {
    	v[x]=max(v[ls[x]],v[rs[x]]);
    	s[x]=(v[ls[x]]>=v[rs[x]])?s[ls[x]]:s[rs[x]];
    }
    void insert(int &x,int a,int b,int l,int r)
    {
    	if(!x)	x=++tot;
    	if(l==r)
    	{
    		v[x]+=b,s[x]=ref[l];
    		return ;
    	}
    	int mid=l+r>>1;
    	if(a<=mid)	insert(ls[x],a,b,l,mid);
    	else	insert(rs[x],a,b,mid+1,r);
    	pushup(x);
    }
    void merge(int &a,int b,int l,int r)
    {
    	if(!b)	return ;
    	if(!a)
    	{
    		a=b;
    		return ;
    	}
    	if(l==r)
    	{
    		v[a]+=v[b];
    		return ;
    	}
    	int mid=l+r>>1;
    	merge(ls[a],ls[b],l,mid),merge(rs[a],rs[b],mid+1,r);
    	pushup(a);
    }
    int main()
    {
    	int i,j,a,b,c,d;
    	n=rd(),m=rd();
    	for(i=1;i<=n;i++)	rt[i]=++tot;
    	for(i=1;i<n;i++)	a=rd(),b=rd(),add(a,b),add(b,a);
    	dep[1]=1,dfs(1);
    	for(j=1;(1<<j)<=n;j++)	for(i=1;i<=n;i++)	fa[j][i]=fa[j-1][fa[j-1][i]];
    	for(i=1;i<=m;i++)	q[i].a=rd(),q[i].b=rd(),q[i].c=rd();
    	sort(q+1,q+m+1,cmp);
    	for(d=0,i=1;i<=m;i++)
    	{
    		a=q[i].a,b=q[i].b,c=lca(a,b);
    		if(q[i].c>q[i-1].c)	ref[++d]=q[i].c;
    		insert(rt[a],d,1,0,m),insert(rt[b],d,1,0,m),insert(rt[c],d,-1,0,m);
    		if(c!=1)	insert(rt[fa[0][c]],d,-1,0,m);
    	}
    	for(i=n;i>1;i--)	merge(rt[fa[0][p[i]]],rt[p[i]],0,m);
    	for(i=1;i<=n;i++)	printf("%d
    ",s[rt[i]]);
    	return 0;
    }
  • 相关阅读:
    20199118 2019-2020-2《网络攻防实践》第七周作业
    20199118 2019-2020-2 《网络攻防实践》第六周作业
    20199118 2019-2020-2 《网络攻防实践》第五周作业
    20199118《网络攻防实践》第四周作业
    C#调用webservice 不用默认配置文件 直接在构造函数配置地址
    SQL 字符串分隔函数
    查询Sqlserver数据库死锁的一个存储过程
    C# 守护进程 Windows服务 启动 exe
    SQLSERVER 存储过程中的事务
    EFCore连接Mysql DBFirst模式生成model
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/7277943.html
Copyright © 2011-2022 走看看