link

题解

考虑B部分的做法。

通过分治找到每个点的父亲。

对于一个区间,考虑父亲在这个区间内的点,如果在左半边则父亲一定在左半边,否则,先modify一下左半边的每个点,如果这个点改变了则它的父亲在左半边,否则在右半边。接着对左右半边分治下去。

发现当一个点前面有奇数个点的时候,这样的操作一定可以找到恰好一个父亲

于是每次shuffle一次,做一次上述操作,删掉孤立点。

不过最前面的暴力部分和B要另写。

#include "explore.h"
#include<bits/stdc++.h>
using namespace std;
int a[200005],b[200005],ls[200005];
int t,fn;
vector<int> s[400005];
vector<int> to[200005];
void xreport(int x,int y){
    x=a[x];y=a[y];
    report(x,y);
    ++fn;
    to[x].push_back(y);
    to[y].push_back(x);
}
int xquery(int x){
    x=a[x];
    int w=query(x);
    for(auto i:to[x])w^=b[i];
    return w;
}
void solve(int l,int r,int rt){
    if(l==r){
        int n=s[rt].size();
        for(int i=0;i<n;++i)if(s[rt][i]!=l)xreport(l,s[rt][i]);
    }
    else{
        int mid=(l+r)>>1;
        int x=t;
        for(int i=l;i<=mid;++i){modify(a[i]);b[a[i]]=1;}
        t+=2;
        int n=s[rt].size();
        for(int i=0;i<n;++i)if(s[rt][i]<=mid || xquery(s[rt][i])){ s[x+1].push_back(s[rt][i]);
        }
        else s[x+2].push_back(s[rt][i]);
        for(int i=l;i<=mid;++i){modify(a[i]);b[a[i]]=0;}
        solve(l,mid,x+1);    
        solve(mid+1,r,x+2);    
    }
    s[rt].clear();
}

void solveB(int l,int r,int rt){
    if(l==r){
        int n=s[rt].size();
        for(int i=0;i<n;++i)if(s[rt][i]!=l)report(l,s[rt][i]);
        return;
    }
    else{
        int mid=(l+r)>>1;
        int x=t;
        for(int i=l;i<=mid;++i)modify(i);
        t+=2;
        int n=s[rt].size();
        for(int i=0;i<n;++i)if(s[rt][i]<=mid || query(s[rt][i])){
            s[x+1].push_back(s[rt][i]);
        }
        else s[x+2].push_back(s[rt][i]);
        for(int i=l;i<=mid;++i)modify(i);
        solveB(l,mid,x+1);    
        solveB(mid+1,r,x+2);    
    }
}
void explore(int n, int m) {
    if(n%10==7){
        t=1;
        for(int i=0;i<n;++i)s[t].push_back(i);
        solveB(0,n-1,t);

        return ;
    }
    else if(n<=500){
        for(int i=0;i<n-1;++i){
            modify(i);
            for(int j=i+1;j<n;++j){
                if(query(j)!=ls[j]){
                    ls[j]^=1;
                    report(i,j);
                }
            }
        }
        return;
    }
    for(int i=0;i<n;++i){
        a[i]=i;
    }
    do{
        random_shuffle(a,a+n);    
        t=1;
        for(int i=0;i<n;++i)s[1].push_back(i);
        solve(0,n-1,1);
        if(fn<m){
            for(int i=0;i<n;++i)if(check(a[i])){swap(a[i],a[--n]);--i;}
        }
    }while(fn<m);
    t=1;
    for(int i=0;i<n;++i)s[t].push_back(i);
}

标签: 交互, 随机化

添加新评论