BZOJ4025 二分图 线段树分治、带权并查集

传送门


如果边不会消失,那么显然可以带权并查集做(然后发现自己不会写带权并查集

但是每条边有消失时间。这样每一条边产生贡献的时间对应一段区间,故对时间轴建立线段树,将每一条边扔到线段树对应的点上。

然后遍历整棵线段树,每遍历到一个点将覆盖这个点对应区间的边全部加入带权并查集中,递归到叶子节点输出答案。回溯的时候把在这一个点加入的边从并查集中栈序撤销。

因为需要撤销所以并查集不能使用路径压缩,只能按秩合并。

#include<iostream>
#include<cstdio>
#include<stack>
#include<vector>
//This code is written by Itst
using namespace std;

inline int read(){
    int a = 0;
    char c = getchar();
    while(!isdigit(c))
        c = getchar();
    while(isdigit(c)){
        a = a * 10 + c - 48;
        c = getchar();
    }
    return a;
}

const int MAXN = 1e5 + 7;
int N , M , T;

#define PII pair < int , int >
#define st first
#define nd second
#define mid ((l + r) >> 1)
#define lch (x << 1)
#define rch (x << 1 | 1)
vector < PII > Edge[MAXN << 2];
void addEd(int x , int l , int r , int L , int R , PII Ed){
    if(l >= L && r <= R){
        Edge[x].push_back(Ed);
        return;
    }
    if(mid >= L) addEd(lch , l , mid , L , R , Ed);
    if(mid < R) addEd(rch , mid + 1 , r , L , R , Ed);
}

struct node{
    int fa , val , sz;
}dsu[MAXN];

PII find(int x){
    if(dsu[x].fa == x) return PII(x , 0);
    PII t = find(dsu[x].fa);
    return PII(t.st , t.nd ^ dsu[x].val);
}

void solve(int x , int l , int r , bool f){
    stack < int > stk;
    for(vector < PII > :: iterator t = Edge[x].begin() ; t != Edge[x].end() ; ++t){
        int p = (*t).st , q = (*t).nd;
        PII M = find(p) , N = find(q);
        int m = M.st , n = N.st;
        if(m != n){
            if(dsu[m].sz > dsu[n].sz)
                swap(n , m);
            dsu[n].sz += dsu[m].sz;
            dsu[m].fa = n;
            dsu[m].val = M.nd ^ N.nd ^ 1;
            stk.push(m);
        }
        else
            f &= (M.nd ^ N.nd);
    }
    if(l == r)
        puts(f ? "Yes" : "No");
    else{
        solve(lch , l , mid , f);
        solve(rch , mid + 1 , r , f);
    }
    while(!stk.empty()){
        int t = stk.top(); stk.pop();
        dsu[dsu[t].fa].sz -= dsu[t].sz;
        dsu[t].val = 0; dsu[t].fa = t;
    }
}

int main(){
#ifndef ONLINE_JUDGE
    freopen("in","r",stdin);
    freopen("out","w",stdout);
#endif
    N = read(); M = read(); T = read();
    for(int i = 1 ; i <= M ; ++i){
        int a = read() , b = read() , l = read() , r = read();
        if(l < r)
            addEd(1 , 1 , T , l + 1 , r , PII(a , b));
    }
    for(int i = 1 ; i <= N ; ++i){
        dsu[i].fa = i;
        dsu[i].sz = 1;
    }
    solve(1 , 1 , T , 1);
    return 0;
}

转载于:https://www.cnblogs.com/Itst/p/10624143.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在信号处理领域,DOA(Direction of Arrival)估计是一项关键技术,主要用于确定多个信号源到达接收阵列的方向。本文将详细探讨三种ESPRIT(Estimation of Signal Parameters via Rotational Invariance Techniques)算法在DOA估计中的实现,以及它们在MATLAB环境中的具体应用。 ESPRIT算法是由Paul Kailath等人于1986年提出的,其核心思想是利用阵列数据的旋转不变性来估计信号源的角度。这种算法相比传统的 MUSIC(Multiple Signal Classification)算法具有较低的计算复杂度,且无需进行特征值分解,因此在实际应用中颇具优势。 1. 普通ESPRIT算法 普通ESPRIT算法分为两个主要步骤:构造等效旋转不变系统和估计角度。通过空间平移(如延时)构建两个子阵列,使得它们之间的关系具有旋转不变性。然后,通过对子阵列数据进行最小二乘拟合,可以得到信号源的角频率估计,进一步转换为DOA估计。 2. 常规ESPRIT算法实现 在描述中提到的`common_esprit_method1.m`和`common_esprit_method2.m`是两种不同的普通ESPRIT算法实现。它们可能在实现细节上略有差异,比如选择子阵列的方式、参数估计的策略等。MATLAB代码通常会包含预处理步骤(如数据归一化)、子阵列构造、旋转不变性矩阵的建立、最小二乘估计等部分。通过运行这两个文件,可以比较它们在估计精度和计算效率上的异同。 3. TLS_ESPRIT算法 TLS(Total Least Squares)ESPRIT是对普通ESPRIT的优化,它考虑了数据噪声的影响,提高了估计的稳健性。在TLS_ESPRIT算法中,不假设数据噪声是高斯白噪声,而是采用总最小二乘准则来拟合数据。这使得算法在噪声环境下表现更优。`TLS_esprit.m`文件应该包含了TLS_ESPRIT算法的完整实现,包括TLS估计的步骤和旋转不变性矩阵的改进处理。 在实际应用中,选择合适的ESPRIT变体取决于系统条件,例如噪声水平、信号质量以及计算资源。通过MATLAB实现,研究者和工程师可以方便地比较不同算法的效果,并根据需要进行调整和优化。同时,这些代码也为教学和学习DOA估计提供了一个直观的平台,有助于深入理解ESPRIT算法的工作原理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值