【2021牛客暑期多校训练营3】G. Yu Ling(Ling YueZheng) and Colorful Tree

Description

给你一棵n个点1为根的有根树,边有长度,点x有点权 a [ x ] a[x] a[x],你需要支持以下两操作:

  1. 将点x的点权修改成v;
  2. 询问点x到根的路径上,距离x最近的点y,满足 L ≤ a [ y ] ≤ R L\leq a[y]\leq R La[y]R 且a[y]%v==0,其中x,L,R,v给出;

保证操作1的v两两不同且 1 ≤ v ≤ n 1\leq v \leq n 1vn,一开始权值均为0

n , m ≤ 1.1 ∗ 1 0 5 n,m \leq 1.1*10^5 n,m1.1105

Solution

因为查询是询问祖先后代链的答案,考虑每次修改操作修改整棵子树,这样查询就是单点查询了,

离线,枚举询问的v,把所有v倍数的修改操作列出来,
然后CDQ分治,每次计算l–mid中的修改操作对mid+1–r的查询操作的影响,
本来是三个限制条件的:时间t,dfs序,询问的LR,
现在通过分治去掉了时间t的限制,剩下两个又可以通过排序去掉一个dfs序的限制,
最后用线段树即可处理询问的LR的限制,

注意到操作1的v是两两不同的,所以每个修改只会出现log次。

复杂度: O ( n log ⁡ 3 ( n ) ) O(n\log^3(n)) O(nlog3(n))

Code


#include <bits/stdc++.h>
#define fo(i,a,b) for(int i=a;i<=b;++i)
#define fod(i,a,b) for(int i=a;i>=b;--i)
#define efo(i,a) for(int i=0;i<(int)B[q].size();++i)
using namespace std;
typedef long long LL;
typedef pair<int,int> pii;
const int N=120500;
int read(int &n)
{
	bool q=0;n=0;char ch=' ';
	for(;ch!='-'&&(ch<'0'||ch>'9');ch=getchar());
	if(ch=='-')ch=getchar(),q=1;
	for(;ch>='0'&&ch<='9';ch=getchar())n=(n<<3)+(n<<1)+ch-48;
	return q?n=-n:n;
}

int n,m,ans;
vector<int>B[N],Bv[N];
int sc[N][5];
LL Ans[N];
int dfn[N],Si[N],dep[N];
LL dis[N];
void link(int q,int w,int e)
{
	B[q].push_back(w);Bv[q].push_back(e);
	B[w].push_back(q);Bv[w].push_back(e);
}
int dfsf(int q,int fa,int fav,int c)
{
	dis[q]=dis[fa]+fav;
	dfn[q]=++dfn[0];dep[q]=c;
	efo(i,q)if(B[q][i]!=fa)Si[q]+=dfsf(B[q][i],q,Bv[q][i],c+1);
	return ++Si[q];
}


LL tr[N*4];
void change(int l1,LL l2,int l=1,int r=n,int e=1)
{
	if(l==r)
	{
		tr[e]=l2;
		return;
	}
	int mid=(l+r)>>1;
	if(l1<=mid)change(l1,l2,l,mid,e<<1);
	else change(l1,l2,mid+1,r,e<<1|1);
	tr[e]=max(tr[e<<1],tr[e<<1|1]);
}
LL find(int l1,int r1,int l=1,int r=n,int e=1)
{
	if(l1<=l&&r<=r1)return tr[e];
	int mid=(l+r)>>1;
	LL ans=0;
	if(l1<=mid)ans=find(l1,r1,l,mid,e<<1);
	if(mid<r1)ans=max(ans,find(l1,r1,mid+1,r,e<<1|1));
	return ans;
}

struct Val
{
	int ty,i,q,w,e;
}as[N];
vector<int>oc[N],oa[N];
int p[N*2];

vector<Val>h[N];
void divide(int l,int r)
{
	if(l>=r)return;
	int mid=(l+r)>>1;

	p[0]=0;
	int mx=0;
	fo(i,l,mid)if(as[i].ty==0)
	{
		h[dfn[as[i].q]].push_back({0,as[i].i,as[i].w,as[i].q,0});
		h[dfn[as[i].q]+Si[as[i].q]].push_back({0,as[i].i,as[i].w,0,0});
		mx=max(mx,as[i].w);
		p[++p[0]]=dfn[as[i].q];
		p[++p[0]]=dfn[as[i].q]+Si[as[i].q];
	}
	int pl=p[0];
	fo(i,mid+1,r)if(as[i].ty==1)
	{
		h[dfn[as[i].q]].push_back({1,as[i].i,as[i].w,as[i].e,as[i].q});
		p[++p[0]]=dfn[as[i].q];
	}

	if(pl && p[0]>pl)
	{
		sort(p+1,p+1+p[0]);
		p[0]=unique(p+1,p+1+p[0])-p-1;
		fo(I,1,p[0])
		{
			int i=p[I];

			for(int j=0;j<(int)h[i].size();++j)
			{
				if(h[i][j].ty==0)
				{
					change(h[i][j].q,dis[h[i][j].w],1,mx);
				}
				else if(h[i][j].q<=h[i][j].w && h[i][j].q<=mx){
					LL t=find(h[i][j].q,h[i][j].w,1,mx);
					if(t)
					{
						Ans[h[i][j].i]=min(Ans[h[i][j].i],dis[h[i][j].e]-t);
					}
				}
			}
			h[i].clear();
		}
	}else fo(i,1,p[0])h[p[i]].clear();

	divide(l,mid);
	divide(mid+1,r);
}
int main()
{
	freopen("!.in","r",stdin);
	freopen("1.out","w",stdout);
	int q,w,e,m1;
	read(n),read(m1);
	fo(i,1,n-1)read(q),read(w),read(e),link(q,w,e);
	dfsf(1,0,1,1);
	fo(i,1,m1)
	{
		fo(j,0,2)read(sc[i][j]);
		if(sc[i][0])read(sc[i][3]),read(sc[i][4]),oa[sc[i][4]].push_back(i),Ans[i]=1e18;
		else oc[sc[i][2]].push_back(i);
	}

	fo(I,1,n)
	{
		m=0;
		for(int j=I;j<=n;j+=I)
		{
			for(int k=0;k<(int)oc[j].size();++k)
			{
				++m;
				as[m].ty=0;
				as[m].i=oc[j][k];
				as[m].q=sc[oc[j][k]][1];
				as[m].w=sc[oc[j][k]][2]/I;
			}
		}
		q=m;
		for(int k=0;k<(int)oa[I].size();++k)
		{
			++m;
			as[m].ty=1;
			as[m].i=oa[I][k];
			as[m].q=sc[oa[I][k]][1];
			as[m].w=max(1,(sc[oa[I][k]][2]-1)/I+1);
			as[m].e=sc[oa[I][k]][3]/I;
		}
		sort(as+1,as+1+m,[](Val q,Val w){return q.i<w.i;});
		if(!q||q==m)continue;

		divide(1,m);
	}

	fo(i,1,m1)if(sc[i][0])
	{
		if(Ans[i]>=1e18)printf("Impossible!\n");
		else printf("%lld\n",Ans[i]);
	}
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C语言是一种广泛使用的编程语言,它具有高效、灵活、可移植性强等特点,被广泛应用于操作系统、嵌入式系统、数据库、编译器等领域的开发。C语言的基本语法包括变量、数据类型、运算符、控制结构(如if语句、循环语句等)、函数、指针等。在编写C程序时,需要注意变量的声明和定义、指针的使用、内存的分配与释放等问题。C语言中常用的数据结构包括: 1. 数组:一种存储同类型数据的结构,可以进行索引访问和修改。 2. 链表:一种存储不同类型数据的结构,每个节点包含数据和指向下一个节点的指针。 3. 栈:一种后进先出(LIFO)的数据结构,可以通过压入(push)和弹出(pop)操作进行数据的存储和取出。 4. 队列:一种先进先出(FIFO)的数据结构,可以通过入队(enqueue)和出队(dequeue)操作进行数据的存储和取出。 5. 树:一种存储具有父子关系的数据结构,可以通过中序遍历、前序遍历和后序遍历等方式进行数据的访问和修改。 6. 图:一种存储具有节点和边关系的数据结构,可以通过广度优先搜索、深度优先搜索等方式进行数据的访问和修改。 这些数据结构在C语言中都有相应的实现方式,可以应用于各种不同的场景。C语言中的各种数据结构都有其优缺点,下面列举一些常见的数据结构的优缺点: 数组: 优点:访问和修改元素的速度非常快,适用于需要频繁读取和修改数据的场合。 缺点:数组的长度是固定的,不适合存储大小不固定的动态数据,另外数组在内存中是连续分配的,当数组较大时可能会导致内存碎片化。 链表: 优点:可以方便地插入和删除元素,适用于需要频繁插入和删除数据的场合。 缺点:访问和修改元素的速度相对较慢,因为需要遍历链表找到指定的节点。 栈: 优点:后进先出(LIFO)的特性使得栈在处理递归和括号匹配等问题时非常方便。 缺点:栈的空间有限,当数据量较大时可能会导致栈溢出。 队列: 优点:先进先出(FIFO)的特性使得

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值