BZOJ 3069 [LCT][并查集][双连通分量]

Description

Byteasar是一个很纠结的人。每次他经过Bytetown的时候都知道有至少2条不同的路径可以选择,这导致他必须花很长时间来决定走哪条路。Byteasar最近听说了Bytetown的修路计划,他可能是唯一一个为此感到高兴的人——他有机会消除他的烦恼。
在Byteasar一共有n个岔口,连接着m条双向道路。两条路径完全不同当且仅当他们没有公共的道路(但是允许经过相同的岔口)。
Byteasar想知道:对于两个岔口x y,是否存在一对完全不同的路径。

Solution

%%%Claris
这里写图片描述

可能是自己sb了。。。居然调了那么久,看来以后LCT必须要很熟练的写啊。。。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;

const int N = 301010;
const int INF = 1 << 30;

inline char get(void) {
  static char buf[100000], *S = buf, *T = buf;
  if (S == T) {
    T = (S = buf) + fread(buf, 1, 100000, stdin);
    if (S == T) return EOF; 
  }
  return *S++;
}
inline void read(int &x) {
  static char c; x = 0;
  for (c = get(); c < '0' || c > '9'; c = get());
  for (; c >= '0' && c <= '9'; c = get()) x = x * 10 + c - '0';
}
inline void readopt(int &opt) {
  static char c;
  for (c = get(); c != 'Z' && c != 'P'; c = get());
  opt = (c == 'Z');
}

int n, m, q, Gcnt, x, y, z, cnt;
int a[N], b[N];
int fa[N], rk[N];
int ans[N];
struct Qry {
  int opt, x, y, id;
  inline friend bool operator <(const Qry &a, const Qry &b) {
    return a.id > b.id;
  }
};
Qry Q[N];
vector<int> e[N], g[N];

inline int Fa(int x) {
  return fa[x] == x ? x : fa[x] = Fa(fa[x]);
}
inline int Merge(int x, int y) {
  static int f1, f2;
  f1 = Fa(x); f2 = Fa(y);
  if (f1 == f2) return false;
  if (rk[f1] > rk[f2]) swap(f1, f2);
  if (rk[f1] == rk[f2]) rk[f2]++;
  fa[f1] = f2; return 1;
}

namespace LCT {
  int f[N];
  bool br[N], st[N], sm[N];
  int ch[N][2];
  bool rev[N];
  int sta[N];
  inline bool IsRoot(int x) {
    return ch[f[x]][0] != x && ch[f[x]][1] != x;
  }
  inline void PushDown(int x) {
    if (rev[x]) {
      rev[ch[x][0]] ^= 1; rev[ch[x][1]] ^= 1;
      swap(ch[x][0], ch[x][1]); rev[x] = 0;
    }
    if (st[x]) {
      st[ch[x][0]] = st[ch[x][1]] = 1;
      br[ch[x][0]] = br[ch[x][1]] = 0;
      sm[ch[x][0]] = sm[ch[x][1]] = 0;
      st[x] = 0;
    }
  }
  inline void PushUp(int x) {
    sm[x] = br[x] | sm[ch[x][0]] | sm[ch[x][1]];
  }
  inline void Rotate(int x) {
    int y = f[x], z = f[y],
      l = (ch[y][0] != x), r = l ^ 1;
    if (!IsRoot(y)) {
      if (ch[z][0] == y) ch[z][0] = x;
      else ch[z][1] = x;
    }
    f[x] = z; f[y] = x; f[ch[x][r]] = y;
    ch[y][l] = ch[x][r]; ch[x][r] = y;
    PushUp(y); PushUp(x);
   }
  void Splay(int x) {
    int top = 0; sta[++top] = x;
    for (int i = x; !IsRoot(i); i = f[i])
      sta[++top] = f[i];
    while (top) PushDown(sta[top--]);
    while (!IsRoot(x)) {
      int y = f[x], z = f[y];
      if (!IsRoot(y)) {
        if (ch[y][0] == x ^ ch[z][0] == y) Rotate(x);
        else Rotate(y);
      }
      Rotate(x);
    }
  }
  void Access(int x) {
    for (int t = 0; x; x = f[x]) {
      Splay(x); ch[x][1] = t;
      PushUp(x); t = x;
    }
  }
  void MakeRoot(int x) {
    Access(x); Splay(x); rev[x] ^= 1;
  }
  void Link(int x, int y) {
    MakeRoot(x); f[x] = y;
  }
  void MakePath(int x, int y) {
    MakeRoot(x); Access(y); Splay(y);
  }
  void Cut(int x, int y) {
    MakePath(x, y);
    ch[y][0] = f[x] = 0; PushUp(y);
  }
};
using namespace LCT;

void AddEdge(int x, int y, int z) {
  if (Merge(x, y)) {
    Link(x, z); Link(y, z);
    br[z] = sm[z] = 1;
  } else {
    MakePath(x, y);
    st[y] = 1; sm[y] = br[y] = 0;
  }
}
int Query(int x, int y) {
  if (Fa(x) != Fa(y)) return 1;
  MakePath(x, y); return sm[y];
}

int main(void) {
  read(n); read(m); read(q); cnt = n;
  for (int i = 1; i <= n; i++) {
    fa[i] = i; e[i].push_back(INF);
  }
  for (int i = 1; i <= m; i++) {
    read(x); read(y);
    if (x > y) swap(x, y);
    a[i] = x; b[i] = y;
  }
  for (int i = 1; i <= q; i++) {
    readopt(Q[i].opt);
    read(Q[i].x); read(Q[i].y);
    if (Q[i].x > Q[i].y) swap(Q[i].x, Q[i].y);
    if (Q[i].opt) e[Q[i].x].push_back(Q[i].y);
  }
  for (int i = 1; i <= n; i++)
    sort(e[i].begin(), e[i].end());
  for (int i = 1; i <= m; i++) {
    if (*lower_bound(e[a[i]].begin(), e[a[i]].end(), b[i]) == b[i]) continue;
    AddEdge(a[i], b[i], ++cnt);
  }
  reverse(Q + 1, Q + q + 1);
  for (int i = 1; i <= q; i++) {
    if (Q[i].opt) AddEdge(Q[i].x, Q[i].y, ++cnt);
    else ans[i] = Query(Q[i].x, Q[i].y);
  }
  for (int i = q; i; i--)
    if (!Q[i].opt) printf(ans[i] ? "NIE\n" : "TAK\n");
  return 0;
}
内容概要:本文围绕【语音增强】领域中的组稀疏信号去噪问题展开研究,提出了一种结合非凸正则化与凸优化理论的去噪方法,旨在提升含噪语音信号的可懂度与质量。文章系统阐述了组稀疏信号模型的构建机制,引入非凸正则项以更精确地逼近理想稀疏性,克服传统凸正则化在稀疏表达上的局限性,并采用高效的凸优化算法保障模型求解的稳定性与收敛性。整个算法流程在Matlab平台上完整实现,涵盖语音信号预处理、稀疏系数求解、去噪重构等关键环节,并配套提供可复现的代码资源,便于研究人员进一步验证与拓展。该方法在保留数学可处理性的同时显著增强了去噪性能,尤其适用于低信噪比环境下的语音恢复任务。; 适合人群:具备一定信号与系统、数字信号处理理论基础,熟悉稀疏表示与最优化方法,且拥有Matlab编程能力的研究生、科研人员及从事语音增强、音频工程、通信系统等相关领域的工程技术人员。; 使用场景及目标:①应用于语音通信、智能助听设备、语音识别前端等对语音质量要求较高的实际系统中;②作为高校课程或科研项目中的教学案例,帮助深入理解稀疏表示、非凸优化与凸优化算法的融合机制;③为后续研究非凸正则化在图像去噪、生物医学信号处理等其他稀疏恢复问题中的性能优势提供理论依据与实现范例。; 阅读建议:建议读者结合所提供的Matlab代码逐模块分析,重点理解非凸正则项的设计动机及其对稀疏性的增强作用,深入掌握优化求解过程中迭代算法的实现细节;同时可通过调整正则化参数、测试不同噪声类型(如白噪声、车间噪声)与强度的语音信号,系统评估算法的鲁棒性、收敛速度与去噪效果,从而全面把握该方法的优势与潜在局限。
内容概要:本文系统介绍了节点不连续伽辽金方法(NDG)在求解线性和非线性平流方程中的一维数值实现过程,并配套提供了完整的Matlab代码实现。该方法作为一种高精度、高分辨率的数值离散化技术,特别适用于对流主导的偏微分方程求解,在处理间断解和保持数值稳定性方面具有突出优势。文章详细阐述了NDG方法的核心理论基础,包括弱形式构造、局部基函数选取、数值通量处理、时间推进格式(如显式Runge-Kutta方法)以及边界条件的实施策略。通过多个典型算例(如线性对流、Burgers方程等)的仿真分析,充分验证了该方法在捕捉激波、避免非物理振荡及保持高阶精度方面的有效性。结合代码实践,读者可深入掌握NDG方法的算法设计与编程实现的关键环节。; 适合人群:具备偏微分方程数值解法、有限元方法或计算流体力学基础知识,熟悉Matlab编程语言,从事科学计算、工程仿真、应用数学或相关领域研究的研究生、科研人员及工程师。; 使用场景及目标:①用于高阶数值方法的教学演示与学习,加深对间断伽辽金方法的理解;②应用于流体力学、气象模拟、环境科学等领域中对强对流现象的精确数值模拟;③作为复杂物理系统仿真中对流项高精度离散化的核心技术支撑;④为科研工作者开发定制化求解器提供可复用的算法原型与代码参考。; 阅读建议:建议读者结合Matlab代码逐行调试与运行,对照理论推导理解每个模块的功能实现,重点关注数值通量、质量矩阵和刚度矩阵的构造过程。同时推荐参阅相关经典文献以深化对NDG方法数学理论和收敛性分析的理解,从而更好地将该方法迁移应用于自身研究课题中。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值