1. 程式人生 > >【NOI2015】BZOJ4195程式自動分析(並查集+離散化)

【NOI2015】BZOJ4195程式自動分析(並查集+離散化)

演算法:離散化+並查集

難度:NOIP

首先,易證(資料範圍:10^9那麼大,如果開一個10^9的fa陣列的話,空間肯定超限),此題需要離散化----->方法

all in all,離散化有三步:

1.排序

2.去重(可以用到unique去重函式)

3.二分索引(可以用到lower_bound函式)

離散化之後,將e=1的情況(等式)直接新增到並查集中,之後列舉檢驗不等式是否成立即可,對於它約束的兩個變數,如果在一個集合裡面,那就不可能滿足!如不相等的約束條件都滿足,那就YES。

注意:

  1. fa陣列要開2*n辣麼大(因為離散化後,有辣麼多的數數呀)
  2. 記得給fa陣列賦初值
  3. 記得要請陣列
  4. unique之前一定要先排序,因為它處理的是相鄰元素的重複元素。---> 詳解(彷彿一點也不詳)

程式碼如下:

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <cmath>
#include <cstring>
#define ll long long
#define N 100005
using namespace std;
struct node
{
    int x,y,e;
}a[N];
int lsh[N<<1],fa[N<<1];//因為離散化之後的大小是2*n
int cmp(node a,node b)
{
    return a.e>b.e;
}
int findf(int x)
{
    if(x==fa[x]) return x;
    return fa[x]=findf(fa[x]);
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int cnt=0;
        memset(a,0,sizeof(a));	
        memset(lsh,0,sizeof(lsh));
        memset(fa,0,sizeof(fa));
        int n;
        scanf("%d",&n);
        for(int i = 1;i <= n;i++)
        {
            scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].e);
            lsh[++cnt]=a[i].x;
            lsh[++cnt]=a[i].y;
        }
        sort(lsh+1,lsh+1+cnt);
        int uni=unique(lsh+1,lsh+1+cnt)-lsh;//unique之前要先排序,因為它處理的是相鄰元素的重複元素
        for(int i = 1;i <= n;i++)
        {
           a[i].x=lower_bound(lsh,lsh+uni,a[i].x)-lsh;
           a[i].y=lower_bound(lsh,lsh+uni,a[i].y)-lsh;   
        } 
        for(int i = 1;i <= uni;i++)
        {
        	fa[i]=i;
        }
        sort(a+1,a+n+1,cmp);
        int flag=1;
        for(int i = 1;i <= n;i++)
        {
            int r1=findf(a[i].x);
            int r2=findf(a[i].y);
            if(a[i].e)
            {
                fa[r1]=r2;  
            }else if(r1==r2)
            {
                puts("NO");
                flag=0; 
                break;
            }
        }
        if(flag)    puts("YES");   
    }
    return 0 ;
}