• 【loj 3274】「JOISC 2020 Day2」变色龙之恋【分治】


    传送门

    Solution

    对于任意两个点(x,y),如果它们同时参加会议,得到的颜色只有(1)种,仅有(3)种情况:

    (1.)(x,y)颜色相同

    (2.)(x)喜欢(y)(y)不喜欢(x)

    (3.)(y)喜欢(x)(x)不喜欢(y)

    在这样的情况下我们对(x,y)连边,显然,每个点的度数都是(1)(3)

    如果点(x)的度数是(1),那么这个点(y)一定是与(x)颜色相同的点,直接得到答案

    否则,考虑依次将(x)与它所连的三个点中任选(2)个进行询问,如果找到的是喜欢(x)的点与和(x)颜色相同的点,那么颜色数是(1),否则颜色数是(2),据此,我们就能推断出剩下的一个点就是(x)喜欢的点

    据此,我们就能确定所有(2,3)类型的边,那么剩下的就是我们需要的(1)号类型的边。

    因此,如果我们找到了所有的边,就能用约(6n)次询问得出答案。

    考虑如何快速找边:

    首先,我们考虑在原序列中找到一个极大独立集:这显然可以通过从左至右扫一遍,依次加入当前的独立集(S)进行询问,如果答案是(|S|+1),那么(S)与当前点之间没有边,可已加入。

    找到独立集后,对于独立集外的点,我们在独立集中二分找到它们之间的边。

    现在,我们就剩下剩余部分内部的边了,递归处理即可。

    因为每个点度数(le 3),所以独立集大小(ge)总点数的(frac 14),所以每次将点集的规模缩小到原来的(frac 34),因此总共找独立集的循环数计算一下极限情况也不超过(10n),而找到每一条边都需要(log(n))次查询,一共也大约只需要(3nlog(n))次查询。

    因此复杂度是正确的,可以通过此题。

    Code

    #include "chameleon.h"
    #include <bits/stdc++.h>
    using namespace std;
    const int N=1010;
    vector<int> p[N];
    int vis[N],lov[N],whlov[N];
    inline int ask(int a,int b,int c){
    	vector<int> p;p.push_back(a);p.push_back(b);p.push_back(c);
    	return Query(p);
    }
    inline int ask(vector<int> a,int b){
    	a.push_back(b);
    	return Query(a)==a.size();
    }
    inline int findans(int x,vector<int> v){
    	if(v.size()==1){
    		p[x].push_back(v[0]),p[v[0]].push_back(x);
    		return v[0];
    	}
    	int mid=v.size()>>1;
    	vector<int> L,R;
    	for(int i=0;i<v.size();++i){
    		if(i<mid) L.push_back(v[i]);
    		else R.push_back(v[i]);
    	}
    	if(ask(L,x)) return findans(x,R);
    	else return findans(x,L);
    }
    void Solve(int n){
    	vector<int> ve;
    	for(int i=1;i<=2*n;++i) ve.push_back(i);
    	while(ve.size()){
    		vector<int> duli;
    		vector<int> oth;
    		for(int i=0;i<ve.size();++i){
    			if(!duli.size()||ask(duli,ve[i])) duli.push_back(ve[i]);
    			else oth.push_back(ve[i]);		
    		}
    		for(int i=0;i<oth.size();++i){
    			vector<int> rec=duli;
    			do{
    				int p=findans(oth[i],rec);
    				vector<int> ne;
    				for(int j=0;j<rec.size();++j) if(rec[j]!=p) ne.push_back(rec[j]);
    				rec=ne;
    				if(ask(rec,oth[i])) break;
    			}while(rec.size());
    		}
    		ve=oth;
    	}
    	for(int i=1;i<=2*n;++i){
    		if(p[i].size()==1){
    			if(vis[i]||vis[p[i][0]]) continue;
    			Answer(i,p[i][0]);
    			vis[i]=vis[p[i][0]]=1;
    		}
    		else{
    			for(int j=0;j<=2;++j){
    				if(ask(i,p[i][j],p[i][(j+1)%3])==1){
    					lov[i]=p[i][(j+2)%3];whlov[lov[i]]=i;
    					break;
    				} 
    			}
    		}
    	}
    	for(int i=1;i<=2*n;++i){
    		if(vis[i]) continue;
    		for(int k=0;k<=2;++k){
    			if(p[i][k]==lov[i]||p[i][k]==whlov[i]) continue;
    			if(vis[p[i][k]]) continue;
    			vis[i]=vis[p[i][k]]=1;
    			Answer(i,p[i][k]);
    			break;
    		}
    	}
    }
    
  • 相关阅读:
    Servlet 生命周期、工作原理(转)
    JVM的内存区域划分(转)
    Java的四个基本特性和对多态的理解
    单例模式和多例模式的区别(转)
    TCP/IP协议体系结构简介
    数据库优化性能
    存储过程的优缺点(转)
    ConurrentHashMap和Hashtable的区别
    XML和JSON优缺点
    HashMap和HashTable的区别
  • 原文地址:https://www.cnblogs.com/tqxboomzero/p/14255157.html
Copyright © 2020-2023  润新知