传送门
题目大意: 太长了, 自己看.
思路: 主要是优化一个问题, 向区间连边, 那么就可以用线段树优化, 但是这个带修改点, 也就是要加入新的点, 所以就用主席树来优化建图, 每一个子节点就作为点本身, 然后其他的还是一样, 缩点, 找点权和最小叶子结点即可…
这道题目就作为主席树优化建图的入门题吧.
AC Coide
const int maxm = 1e5 +5;
// 强连通
int dfn[maxn], low[maxn], bel[maxn];
int dfs_id, scc_cnt;
vector<int>g[maxn]; // 原图以及新图
stack<int>st;
int in[maxn], n, m;
void tarjan(int u) {
dfn[u] = low[u] = ++dfs_id;
st.push(u);
for(int i = 0 ; i < sz(g[u]) ; i++ ) {
int v = g[u][i];
if(!dfn[v]) {
tarjan(v);
low[u] = min(low[u],low[v]);
}
else if(!bel[v])
low[u] = min(low[u],dfn[v]);
}
if(low[u] == dfn[u]){
scc_cnt++;
while(1){
int v = st.top();
st.pop();
bel[v] = scc_cnt;
if(v == u) break;
}
}
}
void init() {
dfs_id = scc_cnt = 0; Fill(in, 0);
Fill(dfn, 0); Fill(bel, 0);
for (int i = 1; i <= n; i++) g[i].clear();
}
// 主席树
struct Tree {
int ls, rs, val; // 左右儿子的编号, 和维护的一个值.
}tree[maxn<<1];
int idx = 0, root[maxm], id[maxm];
int a[maxm];
int build(int l, int r) {
int nod = ++idx;
if (l == r) {
id[l] = nod;
tree[nod].val = a[l];
return nod;
}
int mid = (l + r) >> 1;
tree[nod].ls = build(l, mid);
tree[nod].rs = build(mid+1, r);
g[nod].pb(tree[nod].ls);
g[nod].pb(tree[nod].rs);
return nod;
}
int update(int pre, int l, int r, int pos, int val) {
int nod = ++idx; tree[nod] = tree[pre];
if (l == r) {
id[l] = idx;
tree[nod].val = val;
return nod;
}
int mid = (l + r) >> 1;
if (pos <= mid) tree[nod].ls = update(tree[pre].ls, l, mid, pos, val);
else tree[nod].rs = update(tree[pre].rs, mid+1, r, pos, val);
g[nod].pb(tree[nod].ls);
g[nod].pb(tree[nod].rs);
return nod;
}
void query(int id, int l, int r, int ql, int qr, int x) {
if(qr < l || r < ql) return ;
if(ql <= l && r <= qr){
g[x].push_back(id);
return ;
}
int mid = (l + r) >> 1;
query(tree[id].ls, l, mid, ql, qr, x);
query(tree[id].rs, mid + 1, r, ql, qr, x);
}
ll w[maxn];
void solve() {
scanf("%d", &n); init();
for (int i = 1 ; i <= n ; i ++) scanf("%d", a+i);
root[0] = build(1, n); int pre = 0;
scanf("%d", &m);
while(m--) {
int op, x, l, r;
scanf("%d%d%d", &op, &x, &l);
if (op) {
scanf("%d", &r);
query(root[pre], 1, n, l, r, id[x]);
}
else {
root[pre+1] = update(root[pre], 1, n, x, l);
++pre;
}
}
for (int i = 1 ; i <= idx ; i ++) {
if (!dfn[i]) tarjan(i);
}
for (int i = 1 ; i <= idx ; i ++) {
w[bel[i]] += tree[i].val;
for (auto j : g[i]) {
if (bel[i] != bel[j]) {
in[bel[i]]++;
}
}
}
ll ans = INF;
for (int i = 1 ; i<= scc_cnt ; i ++) {
if (in[i]) continue;
ans = min(ans, w[i]);
}
printf("%lld\n", ans);
}