hdu6756 Finding a MEX 2020杭电hdu多校第1场

http://acm.hdu.edu.cn/showproblem.php?pid=6756

比赛时用的对询问分块,赛后测数据要跑10s,卡这题卡了巨久,和队友写了两份代码都T,没时间看其他题了。。。以前写过一些题,就是把修改放在一个修改队列里面,大于sqrt(q)个的时候重构整个某数据结构,于是询问是q*sqrt(q)的,重构时n*sqrt(q)的。

这题就对每个点开个动态开点线段树或者树状数组,由于mex值最大为du[i],所以只要开du[i]的长度,空间是构的。然后把修改放到修改队列里面,不修改a[i]的值。到了询问的时候,去遍历修改队列里面有没有对他有影响的,就去改一下那个点的线段树里的值,然后线段树上二分求出mex值。如果修改队列大于了sqrt(q),那么把修改队列中的所有值更新到a数组中,顺便重构所有的点的线段树。

复杂度是一样的,不过上述算法确实常数很大。。。这n,m,q=1e5,t=10着实顶不住,要是5e4,t=3海星。。。

于是用了题解的对度数分块过了

我们考虑小点和大点,小点询问,直接暴力找旁边所有点的a,小点更新,那么只需要把相邻的大点的树状数组给更新了,大点更新,只更新a[u],大点询问u,首先把相邻的大点v都拿出来,看要不要更新u的树状数组,因为小点已经更新过了,没更新的只有大点的修改,所以不用考虑。

注意考虑重边情况,一开始没去重,wa了一年,然后去重了过了,然而改正错误发现不去重会T掉

#include<bits/stdc++.h>
using namespace std;

const int maxl=1e5+10;

int n,m,q,len,ans;
int a[maxl],du[maxl],up[maxl];
vector<int> e[maxl],bige[maxl];
vector<int> num[maxl],b[maxl]; 
unordered_map<int,int> mp[maxl];

inline void add(int u,int i,int x)
{
	i++;
	while(i<=du[u]+1)
	{
		b[u][i]+=x;
		i+=i&-i;
	}
}

inline void prework()
{
    scanf("%d%d",&n,&m);
    len=350;
    for(register int i=1;i<=n;++i)
    {
        e[i].clear();bige[i].clear();
    	mp[i].clear();du[i]=0;
	    scanf("%d",&a[i]);
    }
    int u,v;
    for(register int i=1;i<=m;++i)
    {
        scanf("%d%d",&u,&v);
        e[u].push_back(v);
        e[v].push_back(u);
    }
    for(int i=1;i<=n;i++)
    {
    	sort(e[i].begin(),e[i].end());
    	e[i].erase(unique(e[i].begin(),e[i].end()),e[i].end());
		du[i]=e[i].size();
	}
    for(int u=1;u<=n;u++)
    {
    	num[u].resize(du[u]+1);
    	for(int i=0;i<=du[u];i++)
    		num[u][i]=0;
    	b[u].resize(du[u]+2);
    	for(int i=0;i<=du[u]+1;i++)
    		b[u][i]=0;
    	up[u]=log2(du[u]+1);
	}
	for(int u=1;u<=n;u++)
    	for(int v:e[u])
    	if(du[v]>len)
    	{ 
    		bige[u].push_back(v);
			if(a[u]<=du[v])
			{
				if(++num[v][a[u]]==1) 
					add(v,a[u],1);
			}
			mp[v][u]=a[u];
		} 
}

inline int qry(int u)
{
	int ans=0,cnt=0;
	for(int i=up[u];i>=0;i--)
	{
		ans+=1<<i;
		if(ans>du[u]+1 || cnt+b[u][ans]<ans)
			ans-=1<<i;
		else
			cnt+=b[u][ans];
	}
	return ans+1-1;
}

inline void mainwork()
{
    int op,u,x,v;
    scanf("%d",&q);
    for(register int t=1;t<=q;++t)
    {
        scanf("%d",&op);
        if(op==1)
        {
        	scanf("%d%d",&u,&x);
        	if(du[u]<=len)
        	{
        		for(int v:bige[u])
        		{
        			if(a[u]<=du[v])
    				{
        				if(--num[v][a[u]]==0)
        					add(v,a[u],-1);
        			}
        			if(x<=du[v])
        			{
        				if(++num[v][x]==1)
        					add(v,x,1);
					}
				}
			}
			a[u]=x;
		}
        else
        {
            scanf("%d",&u);
           	if(du[u]<=len)
           	{
           		for(int i=0;i<=du[u];i++)
				   	num[u][i]=0;
				for(int v:e[u])
				if(a[v]<=du[u])
					++num[u][a[v]];	
				for(int i=0;i<=du[u];i++)
				if(!num[u][i])
				{
					ans=i;
					break;
				}
			}
			else
			{
				for(int v:bige[u])
				{
					if(mp[u][v]==a[v])
						continue;
					if(mp[u][v]<=du[u])
					{
						if(--num[u][mp[u][v]]==0)
							add(u,mp[u][v],-1);
					}
					if(a[v]<=du[u])
					{
						if(++num[u][a[v]]==1)
							add(u,a[v],1);
					}
					mp[u][v]=a[v];
				}
				ans=qry(u);
			}
            printf("%d\n",ans);
        }
    }
}

int main()
{
    int t;
    scanf("%d",&t);
    for(int i=1;i<=t;i++)
    {
        prework();
        mainwork();
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/liufengwei1/article/details/107518952