zoukankan      html  css  js  c++  java
  • loj3161「NOI2019」I 君的探险(随机化,整体二分)

    loj3161「NOI2019」I 君的探险(随机化,整体二分)

    loj

    Luogu

    题解时间

    对于 $ N le 500 $ 的点,毫无疑问可以直接 $ O(n^2) $ 暴力询问解决。

    考虑看起来最好做的 $ B $ 类。

    由于有每个点的父亲编号小于该点的优良特性,很容易想到整体二分。

    考虑用整体二分求出每个点的父亲:

    对于一个分治区间,毫无疑问 $ [l,mid] $ 的节点的父亲在左区间。

    而对于另外一半节点,考虑将左半节点全部modify,此时右半某个节点亮起则说明左半节点至少有一个与之相邻,则其父亲在左半区间内。

    而对于其他数据,我们依然可以大胆尝试类似的做法,只不过要维护已经确定的边的影响,

    并且注意每次将序列随机打乱,同时已经加完边的节点要从序列中删除。

    #include<bits/stdc++.h>
    // #include"explore.h"
    using namespace std;
    typedef long long lint;
    struct pat{int x,y;pat(int x=0,int y=0):x(x),y(y){}bool operator<(const pat &p)const{return x==p.x?y<p.y:x<p.x;}};
    void modify(int x);
    int query(int x);
    void report(int x,int y);
    int check(int x);
    const int N=400011;
    int n,m;
    namespace task500
    {
    bool check(){return n<=500;}
    int tag[N];
    void explore()
    {
    	for(int i=0;i<n-1;i++){modify(i);for(int j=i+1;j<n;j++)if(query(j)!=tag[j]) tag[j]^=1,report(i,j);}
    }
    }
    vector<int> ve[N];int tcnt;
    namespace taskB
    {
    bool check(){return n==99997||n==199997;}
    void fuck(int l,int r,int px)
    {
    	if(l==r){for(auto x:ve[px])if(x!=l) report(l,x);return;}
    	int mid=l+r>>1,ls=++tcnt,rs=++tcnt;
    	for(int i=l;i<=mid;i++) modify(i);
    	for(auto x:ve[px])
    		if(x<=mid||query(x)) ve[ls].push_back(x);
    		else ve[rs].push_back(x);
    	for(int i=l;i<=mid;i++) modify(i);
    	fuck(l,mid,ls),fuck(mid+1,r,rs);
    }
    void explore()
    {
    	tcnt++;for(int i=0;i<n;i++) ve[tcnt].push_back(i);
    	fuck(0,n-1,tcnt);
    }
    }
    namespace tasknormal
    {
    int cnt;
    int a[N],on[N];
    vector<int> to[N];
    void report(int x,int y){::report(x,y);to[x].push_back(y),to[y].push_back(x),cnt++;}
    int query(int x){int ret=::query(x);for(auto y:to[x]) ret^=on[y];return ret;}
    void fuck(int l,int r,int px)
    {
    	if(l==r){for(auto x:ve[px])if(x!=l) report(a[l],a[x]);ve[px].clear();return;}
    	int mid=l+r>>1,ls=++tcnt,rs=++tcnt;
    	for(int i=l;i<=mid;i++) modify(a[i]),on[a[i]]=1;
    	for(auto x:ve[px])
    		if(x<=mid||query(a[x])) ve[ls].push_back(x);
    		else ve[rs].push_back(x);
    	for(int i=l;i<=mid;i++) modify(a[i]),on[a[i]]=0;
    	fuck(l,mid,ls),fuck(mid+1,r,rs);
    	ve[px].clear();
    }
    void explore()
    {
    	for(int i=0;i<n;i++) a[i]=i;
    	while(cnt<m)
    	{
    		random_shuffle(a,a+n);
    		tcnt=1;for(int i=0;i<n;i++) ve[tcnt].push_back(i);
    		fuck(0,n-1,tcnt);if(cnt<m)for(int i=0;i<n;i++)if(check(a[i])){swap(a[i],a[n-1]),n--,i--;}
    	}
    }
    }
    void explore(int n,int m)
    {
    	::n=n,::m=m;
    	if(task500::check()) task500::explore();
    	else if(taskB::check()) taskB::explore();
    	else tasknormal::explore();
    }
    
  • 相关阅读:
    hdu 3006 The Number of set(思维+壮压DP)
    Mysql-SQL优化-统计某种类型的个数
    canvas.clipPath canvas.clipRect() 无效的原因
    linux下alias命令具体解释
    使用带粒子效果的 CAEmitterLayer
    Wordpress 建站(一)
    一个有趣的问题:ls -l显示的内容中total究竟是什么?
    (转)奇妙的数据挖掘
    android几个高速打包命令
    hdu3336解读KMP算法的next数组
  • 原文地址:https://www.cnblogs.com/rikurika/p/13298818.html
Copyright © 2011-2022 走看看