zoukankan      html  css  js  c++  java
  • luogu P5311 [Ynoi2011]成都七中

    首先考虑判断两个点 (a,b) 在一个询问 ((l,r,x)) 下连通:(path(a,b)) 上的点的编号都在 (l sim r) 之间,可以用倍增预处理。

    对原树建立点分树。对于每个询问 ((l,r,x)),我们考虑找到这样一个点:

    1. 这个点是 (x) 在点分树上的祖先
    2. 这个点与 (x) 连通
    3. 满足以上两个条件的情况下,要求这个点的深度尽可能小

    设找到的这个点为 (y)。因为在原树上的连通块放到点分树上后他们的LCA一定在这个连通块内,那么所有与 (x) 连通的点都必然在 (y) 的子树(点分树)内。我们把这个询问离线下来插进 (y) 里。然后这个询问就和 (x) 没有关系了。

    然后对于点分树上每个点 (x),对于它的子树上的一个点 (p),设 (path(x,p)) 上编号最大的点为 (mx),编号最小的点为 (mn),那么他们连通的条件就是 (mngeq l)(mxleq r)。那么和我们像 HH的项链 这题一样处理二维偏序和颜色种类就好了。

    代码:

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<iostream>
    #include<vector>
    #include<ctime>
    
    using namespace std;
    
    const int N=100009;
    int head[N],cnt,n,q,ans[N],F[N],root,col[N];
    struct Edge
    {
    	int nxt,to;
    }g[N*2];
    struct Tree
    {
    	int head[N],cnt,del[N],siz[N];
    	int dep[N],f[N][30],fmin[N][30],fmax[N][30];
    	
    	struct Edge
    	{
    		int nxt,to;
    	}g[N*2];
    	
    	void add(int from,int to)
    	{
    		g[++cnt].nxt=head[from];
    		g[cnt].to=to;
    		head[from]=cnt;
    	}
    	
    	void dfs(int x,int fa)
    	{
    		siz[x]=1;
    		for (int i=head[x];i;i=g[i].nxt)
    		{
    			int v=g[i].to;
    			if(v==fa||del[v])
    				continue;
    			dfs(v,x);
    			siz[x]+=siz[v];
    		}
    	}
    	
    	int Get_Weight(int x)
    	{
    		dfs(x,-1);
    		int k=siz[x]/2,fa=-1;
    		while(1)
    		{
    			int tmp=0;
    			for (int i=head[x];i;i=g[i].nxt)
    			{
    				int v=g[i].to;
    				if(v==fa||del[v])
    					continue;
    				if(siz[tmp]<siz[v])
    					tmp=v;
    			}
    			if(siz[tmp]<=k)
    				return x;
    			fa=x,x=tmp;
    		}
    	}
    	
    	void DFS(int x,int fa)
    	{
    		fmin[x][0]=fmax[x][0]=x;
    		for (int i=head[x];i;i=g[i].nxt)
    		{
    			int v=g[i].to;
    			if(v==fa)
    				continue;
    			dep[v]=dep[x]+1;
    			f[v][0]=x;
    			DFS(v,x);
    		}
    	}
    	
    	pair<int,int> Get_Min_Max(int x,int y)
    	{
    		int Min=1<<30,Max=0;
    		if(dep[x]!=dep[y])
    		{
    			if(dep[x]<dep[y])
    				swap(x,y);
    			int k=dep[x]-dep[y];
    			for (int i=20;i>=0;i--)
    				if(k>=1<<i)
    					Min=min(Min,fmin[x][i]),
    					Max=max(Max,fmax[x][i]),
    					x=f[x][i],k-=1<<i;
    		}
    		if(x==y)
    			return make_pair(min(Min,x),max(Max,x));
    		for (int i=20;i>=0;i--)
    			if(f[x][i]!=f[y][i])
    				Min=min(Min,min(fmin[y][i],fmin[x][i])),
    				Max=max(Max,max(fmax[y][i],fmax[x][i])),
    				x=f[x][i],y=f[y][i];
    		Min=min(Min,min(fmin[y][0],fmin[x][0]));
    		Max=max(Max,max(fmax[y][0],fmax[x][0]));
    		return make_pair(min(Min,f[x][0]),max(f[x][0],Max));
    	}
    	
    	void work()
    	{
    		memset(fmin,0x3f,sizeof(fmin));
    		add(0,1);
    		DFS(0,-1);
    		for (int j=1;j<=20;j++)
    			for (int i=1;i<=n;i++)
    				f[i][j]=f[f[i][j-1]][j-1],
    				fmin[i][j]=min(fmin[i][j-1],fmin[f[i][j-1]][j-1]),
    				fmax[i][j]=max(fmax[i][j-1],fmax[f[i][j-1]][j-1]);
    	}
    }T;
    struct Question
    {
    	int id,l,r;
    	bool operator < (const Question A)const
    	{
    		return r<A.r;
    	}
    };
    struct BIT
    {
    	#define MaxN 100000
    	int c[N];
    	
    	int lowbit(int x)
    	{
    		return x&-x;
    	}
    	
    	void Modify(int x,int k)
    	{
    		while(x<=MaxN)
    			c[x]+=k,x+=lowbit(x);
    	}
    	
    	int Query(int x)
    	{
    		int ans=0;
    		while(x)
    			ans+=c[x],x-=lowbit(x);
    		return ans;
    	}
    }A;
    struct Bin
    {
    	int l,r,col;
    	bool operator < (const Bin A)const
    	{
    		return r<A.r;
    	}
    };
    Bin bin[N];
    vector <Question> b[N];
    
    void add(int from,int to)
    {
    	g[++cnt].nxt=head[from];
    	g[cnt].to=to;
    	head[from]=cnt;
    }
    
    void init()
    {
    	scanf("%d %d",&n,&q);
    	for (int i=1;i<=n;i++)
    		scanf("%d",&col[i]);
    	for (int i=1,x,y;i<n;i++)
    		scanf("%d %d",&x,&y),
    		T.add(x,y),T.add(y,x);
    	T.work();
    }
    
    void build(int x,int fa)
    {
    	int w=T.Get_Weight(x);
    	T.del[w]=1;
    	if(fa!=-1)
    		add(w,fa),add(fa,w),F[w]=fa;
    	else
    		root=w;
    	for (int i=T.head[w];i;i=T.g[i].nxt)
    	{
    		int v=T.g[i].to;
    		if(T.del[v]) continue;
    		build(v,w);
    	}
    }
    
    int Cnt;
    
    void DFS(int x,int fa,int X)
    {
    	pair<int,int> G=T.Get_Min_Max(X,x);
    	bin[++Cnt]=(Bin){G.first,G.second,col[x]};
    	for (int i=head[x];i;i=g[i].nxt)
    	{
    		int v=g[i].to;
    		if(v==fa)
    			continue;
    		DFS(v,x,X);
    	}
    }
    
    int Maxc[N];
    
    void dfs(int x,int fa)
    {
    	Cnt=0,DFS(x,fa,x);
    	int now=1;
    	sort(b[x].begin(),b[x].end());
    	sort(bin+1,bin+1+Cnt);
    	for (int i=0;i<b[x].size();i++)
    	{
    		Question v=b[x][i];
    		while(bin[now].r<=v.r&&now<=Cnt)
    		{
    			if(Maxc[bin[now].col]==0)
    				A.Modify(bin[now].l,1),
    				Maxc[bin[now].col]=bin[now].l;
    			else if(Maxc[bin[now].col]<bin[now].l)
    				A.Modify(bin[now].l,1),
    				A.Modify(Maxc[bin[now].col],-1),
    				Maxc[bin[now].col]=bin[now].l;
    			now++;
    		}
    //		printf("%d %d
    ",v.r,v.l-1);
    		ans[v.id]=A.Query(v.r)-A.Query(v.l-1);
    	}
    	for (int i=1;i<=Cnt;i++)
    		if(Maxc[bin[i].col]!=0)
    			A.Modify(Maxc[bin[i].col],-1),
    			Maxc[bin[i].col]=0;
    	for (int i=head[x];i;i=g[i].nxt)
    	{
    		int v=g[i].to;
    		if(v==fa)
    			continue;
    		dfs(v,x);
    	}
    }
    
    void print(int x,int fa)
    {
    	for (int i=head[x];i;i=g[i].nxt)
    	{
    		int v=g[i].to;
    		if(v==fa)
    			continue;
    		printf("%d %d
    ",x,v);
    		print(v,x);
    	} 
    }
    
    void work()
    {
    	build(1,-1);
    //	print(root,-1);
    	/*srand(time(0));
    	puts("wyj!!!");
    	for (int i=1;i<=10;i++)
    	{
    		int x=rand()%n+1,y=rand()%n+1;
    		if(x>y) swap(x,y);
    		pair<int,int> G=T.Get_Min_Max(x,y);
    		printf("%d %d %d %d
    ",x,y,G.first,G.second);
    	}*/
    //	pair<int,int> G=T.Get_Min_Max(5,10);
    //	printf("%d %d
    ",G.first,G.second);
    	for (int i=1;i<=q;i++)
    	{
    		int x,y,z;
    		scanf("%d %d %d",&x,&y,&z);
    		int pos=z;
    		for (int j=F[z];j;j=F[j])
    		{
    			pair<int,int> G=T.Get_Min_Max(j,z);
    			if(G.first>=x&&G.second<=y) pos=j;
    		}
    		b[pos].push_back((Question){i,x,y});
    	}
    	dfs(root,-1);
    	for (int i=1;i<=q;i++)
    		printf("%d
    ",ans[i]);
    }
    
    int main()
    {
    	init();
    	work();
    	return 0;
    }
    
    由于博主比较菜,所以有很多东西待学习,大部分文章会持续更新,另外如果有出错或者不周之处,欢迎大家在评论中指出!
  • 相关阅读:
    原型模式
    哈希表原理
    Pow共识算法
    C++虚函数的工作原理
    TCP三次握手与四次分手
    TCP重置报文段及RST常见场景分析
    Ping、Traceroute工作原理
    ARP协议
    Rust生命周期bound用于泛型的引用
    Linux下core dump
  • 原文地址:https://www.cnblogs.com/With-penguin/p/13284442.html
Copyright © 2011-2022 走看看