• luogu P5397 [Ynoi2018]天降之物


    luogu

    下面令(n,q)同阶

    先考虑暴力做法,询问是要对两个位置集合,选两个元素出来,求最小的差的绝对值.因为对于一个元素,一定选另一个集合中和他位置最近的前后两个元素最优,所以暴力是让集合为升序排列,再维护两个指针,一开始指向集合第一个元素,这同时维护之前扫过的元素中两个集合的最后一个元素,然后取出两个指针指向的较小的元素,用这个元素-另一个集合扫过的最后一个元素更新答案

    这题显然没有什么传统数据结构可以维护,所以考虑根号分治,设置一个阈值(lim).先考虑没有修改操作

    • 询问的两个集合大小(le lim),那么直接暴力,这部分复杂度为(O(n*lim))
    • 有一个集合大小(>lim),因为这样的集合个数(le frac{n}{lim})个,所以在一开始先预处理出大小(>lim)的集合和其他集合的答案并且存下来,具体实现可以参考上述暴力做法,询问的时候直接查即可,这部分复杂度为(O(n*frac{n}{lim}))

    (lim=sqrt{n})时取到最优复杂度(O(nsqrt{n}))

    然后是修改操作,修改操作也就是把两个集合合并,如果合并的两个集合大小都(> lim)或都(le lim),复杂度是可以做到(O(n(lim+frac{n}{lim})))的.现在的问题是一个大小(> lim)和大小(le lim)的集合合并.我们考虑把小的集合并到大集合上面去,这里给大集合附加一个集合存合并到大集合上的小集合元素,每次把小集合合并上去,然后如果附加集合大小(>sqrt{n})就把它和大集合合并,并且重新预处理大集合的答案,复杂度(O(n*frac{n}{lim}));询问的时候就先询问大集合预处理的答案,然后对于两个集合的附加集合跑暴力,复杂度(O(n*lim)).这里同样在(lim=sqrt{n})时取到最优复杂度(O(nsqrt{n}))

    #include<bits/stdc++.h>
    #define LL long long
    
    using namespace std;
    const int N=1e5+10,inf=1145141;
    int rd()
    {
        int x=0,w=1;char ch=0;
        while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+(ch^48);ch=getchar();}
        return x*w;	
    }
    int n,m=100001,lm=333,q,ans,sz[N],co[N],pr[N],a[N],ff[N];
    int findf(int x){return ff[x]==x?x:ff[x]=findf(ff[x]);}
    vector<int> st[N],sb[N],an[N],z1,z2;
    vector<int>::iterator it;
    int bg[N],tb;
    void bui(int x)
    {
        for(int i=0;i<=m;++i) an[x][i]=inf;
        an[x][x]=0;
        for(int i=1,ls=-inf;i<=n;++i)
        {
    	    if((a[i]=findf(a[i]))==x) ls=i;
        	else an[x][a[i]]=min(an[x][a[i]],i-ls);
        }
        for(int i=n,ls=inf+inf;i;--i)
        {
    	    if((a[i]=findf(a[i]))==x) ls=i;
        	else an[x][a[i]]=min(an[x][a[i]],ls-i);
        }
    }
    vector<int> merg(vector<int> a,vector<int> b)
    {
        int nn=a.size(),mm=b.size();
        vector<int> an;
        an.resize(nn+mm);
        int pa=0,pb=0,pc=0;
        while(pa<nn&&pb<mm)
        {
        	if(a[pa]<b[pb]) an[pc++]=a[pa],++pa;
    	    else an[pc++]=b[pb],++pb;
        }
        while(pa<nn) an[pc++]=a[pa],++pa;
        while(pb<mm) an[pc++]=b[pb],++pb;
        return an;
    }
    int cn=0;
    
    int main()
    {
        n=rd(),q=rd();
        for(int i=1;i<=n;++i)
        {
        	a[i]=rd()+1,ff[a[i]]=pr[a[i]]=a[i];
        	st[a[i]].push_back(i);
        }
        for(int i=1;i<=m;++i)
        {
        	sz[i]=st[i].size();
        	if(sz[i]>=lm) an[i].resize(m+1),bg[++tb]=i,bui(i);
        }
        while(q--)
        {
        	int op=rd(),x=(rd()^ans)+1,y=(rd()^ans)+1;
        	if(op==1)
        	{
        	    if(x==y) continue;
        	    int lx=x,ly=y;
        	    x=pr[lx],y=pr[ly],pr[lx]=pr[ly]=0;
        	    if(!x||!y){pr[ly]=x+y;continue;}
        	    int yy=ly;
        	    if(sz[x]+(int)sb[x].size()<sz[y]+(int)sb[y].size())
        		swap(x,y),swap(lx,ly);
        	    ff[y]=x,pr[yy]=x;
        	    int lt=tb;tb=0;
        	    for(int i=1;i<=lt;++i)
        	    {
            		if(bg[i]==y) continue;
            		bg[++tb]=bg[i];
            		an[bg[tb]][x]=min(an[bg[tb]][x],an[bg[tb]][y]),an[bg[tb]][y]=inf;
                }
            	if((int)sb[x].size()+sz[y]+(int)sb[y].size()>=lm)
        	    {
            		if(sz[x]<lm) an[x].resize(m+1),bg[++tb]=x;
                	sz[x]+=(int)sb[x].size()+sz[y]+(int)sb[y].size();
            		sz[y]=0,sb[x].clear()/*,st[x].clear(),sb[y].clear(),st[y].clear()*/;
            		bui(x);
    	        }
        	    else
        	    {
            		sb[x]=merg(sb[x],merg(st[y],sb[y]));
            		sz[y]=0/*,st[y].clear(),sb[y].clear()*/;
        	    }
        	}
        	else
        	{
        	    ++cn;
        	    x=pr[x],y=pr[y];
        	    if(!x||!y){puts("Ikaros"),ans=0;continue;}
        	    if(x==y){printf("%d
    ",ans=0);continue;}
        	    ans=inf;
        	    z1=sb[x],z2=sb[y];
        	    if(sz[x]>=lm) ans=min(ans,an[x][y]);
        	    else z1=merg(z1,st[x]);
        	    if(sz[y]>=lm) ans=min(ans,an[y][x]);
        	    else z2=merg(z2,st[y]);
        	    int nn=z1.size(),mm=z2.size();
        	    for(int i=0,j=0,l1=-inf,l2=-inf;i<nn||j<mm;)
        	    {
            		if(i<nn&&(j>=mm||z1[i]<z2[j]))
            		{
            		    ans=min(ans,z1[i]-l2),l1=z1[i];
            		    ++i;
            		}
            		else
            		{
            		    ans=min(ans,z2[j]-l1),l2=z2[j];
            		    ++j;
            		}
        	    }
        	    printf("%d
    ",ans);
        	}
        }
        return 0;
    }
    
  • 相关阅读:
    angluar 判断后跳转加参数
    angular 返回上一页
    angular 组件跳转组件 并传参数
    angluar 表单提交时候报错
    angular 中获取select选中的值
    javascript
    将数据渲染到页面的方式:模版
    将数据渲染到页面的几种方式
    跨域
    ajax
  • 原文地址:https://www.cnblogs.com/smyjr/p/12304887.html
Copyright © 2020-2023  润新知