关键词:并查集,二分图,树剖,树上差分,LCA,搜索。

 

例题一:

CodeForces-85E:Guard Towers

题意:给定平面上N个点(N<=5000),以及N个点的坐标。现在可以把每个点染成红色或者蓝色。求最小化同色点的最大距离,且求出相应的方案数。

思路:二分答案L,把距离大于等于L的连边,然后判定是否是二分图:  对于求方案数,ans=pow(2,cnt),cnt是连通块的数量。因为每个连通块是二分图,一个二分图的染色方案只有两种。 复杂度O(N^2*logL)。

 (当然,最优的解法是转化为切比雪夫距离,复杂度低很多,这里先不管它。)

#include<cstdio>
#include<vector>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=5010;
const int Mod=1e9+7;
vector<int>G[maxn];
int x[maxn],y[maxn],vis[maxn],col[maxn],N;
int qpow(int a,int x){
    int res=1;
    while(x){
        if(x&1) res=(res*1ll*a)%Mod;
        x>>=1;
        a=(a*1ll*a)%Mod;
    }   return res;
}
void read(int &res){
    char c=getchar();res=0;
    for(;c<'0'||c>'9';c=getchar());
    for(;c>='0'&&c<='9';c=getchar()) res=(res<<3)+(res<<1)+c-'0';
}
void init(int len){
    for(int i=1;i<=N;i++) vis[i]=0,G[i].clear();
    for(int i=1;i<=N;i++)
     for(int j=i+1;j<=N;j++){
          int dis=abs(x[i]-x[j])+abs(y[i]-y[j]);
          if(dis>len) {
              G[i].push_back(j);
              G[j].push_back(i);
          }
    }
}
bool dfs(int u,int opt)
{
    vis[u]=1; col[u]=opt; 
    int L=G[u].size();
    for(int i=0;i<L;i++){
        int v=G[u][i];
        if(!vis[v]) {
            if(!dfs(v,opt^1)) return false;
        }
        else if(col[v]==opt) return false;
    }
    return true;
}
bool check(int len)
{
    init(len);
    for(int i=1;i<=N;i++){
        if(!vis[i]) {
            if(!dfs(i,0)) return false;
        }
    }
    return true;
}
int main()
{
    read(N); 
    for(int i=1;i<=N;i++) read(x[i]),read(y[i]);
    int L=0,R=10000,Mid,ans;
    while(L<=R){
        Mid=(L+R)>>1;
        if(check(Mid)) ans=Mid,R=Mid-1;
        else L=Mid+1;
    }
    init(ans); int cnt=0,ans2;
    for(int i=1;i<=N;i++){
        if(!vis[i]){
            cnt++;
            dfs(i,0);
        }
    }
    ans2=qpow(2,cnt);
    printf("%d\n%d\n",ans,ans2);
    return 0;
}
View Code

相关文章: