HDU 4358 分块

产生dfs序列之后,记录每个点对于的L[i]和R[i],每个点对应的子树就确定了。设计一种处理顺序,使得每个点的不被多次重复计算。

对L[i]进行分块,将问题分类,设每块大小为S。同时处理Id=L[i]/S相同的节点:

(1)如果R[i]/S=id,则将该询问放到ask1中

(2)如果R[i]/S!=id,则将该询问放到ask2中。

对于ask1,直接暴力,处理每个问题。复杂度O(√N*√N)=O(N)

对于ask2,先按左端点排序,排序之后,每个节点对应的区间不会相交,应该dfs序列是合法的括号序列,区间一定满足[ [ [ ] ] ]

先处理最外面的节点,再依次删除,逐步回答里面的节点。复杂度(√N*log√N+N)=O(N)

块的个数√N个,所有总的复杂度O(N√N),具体实现键代码:

#include
#include
#include
#include
#include
#include
#include
#define M 100005
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
struct node{
	int x,y,id;
};
mapse;
vectoredge[M];
vectorbucket[M];
vectorask1;
vectorask2;
int L[M],R[M],col[M],T,ds[M],SZ,K;
int ans[M],cnt[M],sum[M];
bool cmp(node A,node B){
	return A.xy)Del(col[ds[R--]]);
		ans[ask2[i].id]=cnt[K];
	}
}
int main(){ 
	int n,m,i,j,a,b,cas,v=1;
	scanf("%d",&cas);
	while(cas--&&scanf("%d %d",&n,&K)){ 
		se.clear();
		int ID=1;
		for(i=1;i<=n;i++){	
			edge[i].clear();
			scanf("%d",&col[i]);
			if(se[col[i]]==0)se[col[i]]=col[i]=ID++;
			else col[i]=se[col[i]];
		}
		for(i=1;i=0;i--)
			bucket[i].clear();
		node tmp;
		for(i=1;i<=n;i++){ 
			tmp.x=L[i],tmp.y=R[i],tmp.id=i;
			bucket[L[i]/SZ].push_back(tmp);
		}
		for(i=0;i<=p;i++){
			 ask1.clear();
		  	 ask2.clear();
		  	 for(j=0;j0) solve1();
			if(ask2.size()>0) solve2(); 	 
		}
		if(v>1)puts("");
		printf("Case #%d:\n",v++);
		scanf("%d",&m);
		for(i=0;i


你可能感兴趣的:(HDU 4358 分块)