对 进行 线段树分治, 将每个 绿绿 的 影响区间分为 个区间散布在 线段树节点 中,
其中 为询问的总数 .
然后对 线段树 , 合并祖先链的和当前节点的绿绿集合 (使用类似归并排序的方法),
由于代价只与 最大生气值 有关, 所以按 生气值 从小到大 排序, 从后往前加入 并查集, 直到有 敌对红红 不得不在一个集合里,
这时保存当前节点贡献, 将数组截止到不合法的位置往下递归 (此时没有遍历到的 绿绿 已无法对答案造成贡献) .
到根节点处统计答案, 时间复杂度
并查集维护方法详见 这道题 .
- 注意判断有效区间是否合法 .
- 并查集合并前需要判断是否有必要 .
- 为什么代码注释处会 啊 .
#include<bits/stdc++.h>
#define reg register
#define pb push_back
int read(){
char c;
int s = 0, flag = 1;
while((c=getchar()) && !isdigit(c))
if(c == '-'){ flag = -1, c = getchar(); break ; }
while(isdigit(c)) s = s*10 + c-'0', c = getchar();
return s * flag;
}
const int maxn = 2000005;
int N;
int M;
int Q_;
int q_cnt;
int F[maxn];
int Ans[maxn];
int match[maxn];
char Smp[5];
struct Grn{ int a, b, l, r, v; } A[maxn];
bool cmp(Grn x, Grn y){ return x.v < y.v; }
std::vector <Grn> B[maxn << 2], P[maxn << 2], Tmp;
struct Node{ int l, r; } T[maxn << 2];
int Find(int x){ return F[x]==x?x:F[x]=Find(F[x]); }
void Build(int k, int l, int r){
T[k].l = l, T[k].r = r;
if(l == r) return ; int mid = l+r >> 1;
Build(k<<1, l, mid), Build(k<<1|1, mid+1, r);
}
void merge(int a, int b){
int t1 = Find(a), t2 = Find(b);
if(t1 == t2) return ;
F[t1] = t2;
}
void Insert(int k, const Grn &aim){
int l = T[k].l, r = T[k].r;
if(aim.l <= l && r <= aim.r) return B[k].pb(aim), void();
int mid = l+r >> 1;
if(aim.l <= mid) Insert(k<<1, aim);
if(aim.r > mid) Insert(k<<1|1, aim);
}
void DFS(int k){
int l = T[k].l, r = T[k].r, res = 0;
int t1 = 0, t2 = 0, len_1 = P[k>>1].size(), len_2 = B[k].size();
Tmp.clear();
while(t1 < len_1 && t2 < len_2){
if(P[k>>1][t1].v < B[k][t2].v) Tmp.pb(P[k>>1][t1 ++]);
else Tmp.pb(B[k][t2 ++]);
}
while(t2 < len_2) Tmp.pb(B[k][t2 ++]);
while(t1 < len_1) Tmp.pb(P[k>>1][t1 ++]);
for(reg int i = 1; i <= 2*N+1; i ++) F[i] = i, match[i] = 0;
for(reg int i = Tmp.size()-1; i >= 0; i --){
int u = Tmp[i].a, v = Tmp[i].b;
if(Find(2*u) == Find(v*2-1)) continue ;
merge(u*2, v*2-1), merge(v*2, u*2-1);
P[k].pb(Tmp[i]);
if(Find(u*2) == Find(u*2-1) || Find(v*2) == Find(v*2-1)){
res = Tmp[i].v;
break ;
}
}
/*
for(reg int i = Tmp.size()-1; i >= 0; i --){
Grn t = Tmp[i];
int a = t.a, b = t.b;
P[k].pb(Tmp[i]);
if(Find(a) == Find(b)){ res = t.v; break ; }
if(!match[a]) match[a] = b;
else merge(match[a], b);
if(!match[b]) match[b] = a;
else merge(match[b], a);
}
*/
if(l == r) return Ans[l] = res, void();
std::reverse(P[k].begin(), P[k].end());
DFS(k<<1), DFS(k<<1|1);
}
int main(){
N = read(), M = read(), Q_ = read();
for(reg int i = 1; i <= M; i ++){
A[i].a = read(), A[i].b = read(), A[i].v = read();
A[i].l = 1, A[i].r = -1;
}
for(reg int i = 1; i <= Q_; i ++){
scanf("%s", Smp);
if(Smp[0] == 'D') A[read()].r = q_cnt;
else if(Smp[0] == 'A'){
A[++ M].a = read(), A[M].b = read(), A[M].v = read();
A[M].l = q_cnt+1, A[M].r = -1;
}else q_cnt ++;
}
Build(1, 1, q_cnt); std::sort(A+1, A+M+1, cmp);
for(reg int i = 1; i <= M; i ++){
if(A[i].r == -1) A[i].r = q_cnt;
if(A[i].l > A[i].r) continue ;
Insert(1, A[i]);
}
DFS(1);
for(reg int i = 1; i <= q_cnt; i ++) printf("%d
", Ans[i]);
return 0;
}