zoukankan      html  css  js  c++  java
  • Ynoi2018 天降之物

    Link
    我们知道在没有修改的时候有一个很简单的根号分治算法,现在考虑将其扩展至带修。
    (cnt_x)(x)的出现次数,(pos_x)(x)的出现位置,(dis_x)(x)到其它数的最短距离。
    (B)为分块大小,(S={x|cnt_x>B})

    这里先给出整体的大致思路:
    保证任意时刻(|pos_x|le B),这样我们可以用(O(B))的时间进行零散的合并/查询。
    如果(|pos_x|>B)那么我们处理(dis_x),很显然处理(dis)的总次数是(O(frac nB))的。

    然后我们给出具体做法:
    最开始先求出(pos,cnt),对于(xin S),清空(pos_x)并求出(dis_x)
    考虑如何处理修改:
    (1.)归并(pos_x,pos_y)并清空(pos_x)
    (2.)如果合并之后(|pos_y|>S),那么清空(pos_y)并更新(dis_y)
    (3.)如果(xin S),那么用(dis_x)更新(dis_y)并清空(dis_x)
    (4.)对所有(win S),用(dis_{w,x})更新(dis_{w,y})
    考虑如何回答询问:
    (1.)先特判(ans=0)的情况。
    (2.)利用(dis_{x,y},dis_{y,x})更新(ans)
    (3.)遍历(pos_x,pos_y)更新(ans)

    不难发现这样做可以完整地维护与统计(pos,dis)的信息。
    总的时间复杂度是(O(nB+frac{n^2}B)),当(B=sqrt n)达到最优(O(n^{1.5}))
    注意到空间复杂度是(O(frac{n^2}B))的,因此可以适当调大(B)来卡空间。

    #include<cmath>
    #include<cstdio>
    #include<cctype>
    #include<vector>
    #include<algorithm>
    #include<unordered_set>
    namespace IO
    {
        char ibuf[(1<<21)+1],*iS,*iT;
        char Get(){return (iS==iT? (iT=(iS=ibuf)+fread(ibuf,1,(1<<21)+1,stdin),(iS==iT? EOF:*iS++)):*iS++);}
        int read(){int x=0,c=Get();while(!isdigit(c))c=Get();while(isdigit(c))x=x*10+c-48,c=Get();return x;}
    }
    using IO::read;
    const int N=100001,B=3,inf=1000000000;
    int n,q,cnt=100000,a[N],fa[N*3],num[N*3],id[N*3];
    std::vector<int>pos[N],dis[N],t;
    std::unordered_set<int>res;
    int find(int x){return fa[x]==x? x:fa[x]=find(fa[x]);}
    int get(int x){return num[find(a[x])];}
    void min(int&a,int b){a=a<b? a:b;}
    void init(int i)
    {
        dis[i].resize(100001,inf);
        for(int j=1,p=0;j<=n;++j)
        {
    	while(p+1<(int)pos[i].size()&&j>pos[i][p]&&j-pos[i][p]>pos[i][p+1]-j) ++p;
    	min(dis[i][get(j)],abs(j-pos[i][p]));
        }
        pos[i].clear(),res.insert(i);
    }
    int main()
    {
        freopen("1.in","r",stdin);freopen("1.out","w",stdout);
        n=read(),q=read();
        for(int i=1;i<=n;++i) pos[a[i]=read()].push_back(i);
        for(int i=1;i<=300000;++i) fa[i]=i;
        for(int i=1;i<=100000;++i) num[i]=id[i]=i;
        for(int i=0;i<=100000;++i) if(pos[i].size()>=B) init(i);
        for(int opt,x,y,ans=0;q;--q)
        {
    	opt=read(),x=read()^ans,y=read()^ans;
    	if(opt==1)
    	{
    	    if(x==y) continue;
    	    num[++cnt]=y,fa[find(id[x])]=fa[find(id[y])]=cnt,id[y]=cnt,id[x]=++cnt,num[id[x]]=x;
    	    t.clear(),t.resize(pos[x].size()+pos[y].size()),std::merge(pos[x].begin(),pos[x].end(),pos[y].begin(),pos[y].end(),t.begin());
    	    pos[x].clear(),pos[y]=t,res.erase(x),res.erase(y);
    	    if(dis[x].size()||dis[y].size())
    	    {
    		if(dis[y].empty()) dis[y].swap(dis[x]);
    		else if(dis[x].size()) {for(int i=0;i<=100000;++i)min(dis[y][i],dis[x][i]);dis[x].clear();}
    		res.insert(y);
    	    }
    	    if(pos[y].size()>=B) init(y);
    	    for(int i:res) min(dis[i][y],dis[i][x]),dis[i][x]=inf;
    	}
    	else
    	{
    	    ans=inf;
    	    if(x==y&&(pos[x].size()||dis[x].size())) ans=0;
    	    if(dis[x].size()) min(ans,dis[x][y]);
    	    if(dis[y].size()) min(ans,dis[y][x]);
    	    for(int i=0,j=0;i<(int)pos[x].size()||j<(int)pos[y].size();)
    		if(i<(int)pos[x].size()&&(j==(int)pos[y].size()||pos[x][i]<pos[y][j])) j? min(ans,pos[x][i]-pos[y][j-1]):void(),++i;
    		else i? min(ans,pos[y][j]-pos[x][i-1]):void(),++j;
    	    ans==inf? puts("Ikaros"),ans=0:printf("%d
    ",ans);
    	}
        }
    }
    
  • 相关阅读:
    Java 1 (JVM、JRE、JDK之间的关系)
    Java 0 (jdk下载安装及环境配置)
    推荐之链接
    idea 2019激活码
    Mock数据使用的Util
    mybatis慢查询配置
    logback参考配置
    Linux网络实时监控配置
    jmeter插件JMeterPlugins-Standard 压力测试
    ZoneDateTime 转换Date
  • 原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/12312161.html
Copyright © 2011-2022 走看看