困难版
题意有些绕 这就不说了 一个点对一个连续区间内的所有点连一条权值相同的边 这个线性的过程可以用线段树来优化
但是这道题中每个位置上的元素会改变 这样只用线段树是无法维护的 需要用主席树来维护 这也没啥好说的 学了主席树其中道理自然明白 然后就是tarjan缩点后贪心 找出度为零的强连通分量加和的最小值
直接上代码
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define N 0x3f3f3f3f3f3f3f3f
struct node1
{
int nl;
int nr;
};
struct node2
{
int v;
int next;
};
stack <int> stk;
node1 tree[2000010];
node2 edge[8000010];
ll val[100010],sum[2000010];
int root[100010],f[100010],mp[100010],fmp[2000010];
int first[2000010],dfn[2000010],low[2000010],book[2000010],belong[2000010],degree[2000010];
int n,q,gou,now,gg,tot,num,cnt;
void addedge(int u,int v)
{
edge[num].v=v;
edge[num].next=first[u];
first[u]=num++;
return;
}
int build(int l,int r)
{
int cur,m;
cur=gou++;
tree[cur].nl=0,tree[cur].nr=0;
if(l==r)
{
mp[l]=cur;
fmp[cur]=l;
return cur;
}
m=(l+r)/2;
tree[cur].nl=build(l,m);
tree[cur].nr=build(m+1,r);
addedge(cur,tree[cur].nl);
addedge(cur,tree[cur].nr);
return cur;
}
int update(int rot,int tar,int l,int r)
{
int cur,m;
cur=gou++;
tree[cur]=tree[rot];
if(l==r)
{
mp[f[tar]]=cur;//
fmp[cur]=f[tar];
return cur;
}
m=(l+r)/2;
if(tar<=m) tree[cur].nl=update(tree[rot].nl,tar,l,m);
else tree[cur].nr=update(tree[rot].nr,tar,m+1,r);
addedge(cur,tree[cur].nl);
addedge(cur,tree[cur].nr);
return cur;
}
void solve(int rot,int tar,int pl,int pr,int l,int r)
{
int m;
if(pl<=l&&r<=pr)
{
addedge(tar,rot);
return;
}
m=(l+r)/2;
if(pl<=m) solve(tree[rot].nl,tar,pl,pr,l,m);
if(pr>m) solve(tree[rot].nr,tar,pl,pr,m+1,r);
return;
}
void dfs(int u)
{
int i,v;
stk.push(u);
book[u]=1;
num++;
dfn[u]=num;
low[u]=num;
for(i=first[u];i!=-1;i=edge[i].next)
{
v=edge[i].v;
if(dfn[v]==0)
{
dfs(v);
low[u]=min(low[u],low[v]);
}
else if(book[v])
{
low[u]=min(low[u],dfn[v]);
}
}
if(dfn[u]==low[u])
{
cnt++;
while(!stk.empty())
{
v=stk.top();
stk.pop();
book[v]=0;
belong[v]=cnt;
if(fmp[v]!=-1) sum[belong[v]]+=val[fmp[v]];
if(u==v) break;
}
}
return;
}
void tarjan()
{
ll minn;
int i,u,v;
while(!stk.empty()) stk.pop();
tot=mp[gg],num=0,cnt=0;
for(i=0;i<=tot;i++)
{
dfn[i]=0;
low[i]=0;
book[i]=0;
belong[i]=0;
sum[i]=0;
degree[i]=0;
}
/*
for(i=1;i<=tot;i++)
{
printf("***%d***\n",i);
for(int j=first[i];j!=-1;j=edge[j].next)
{
printf("%d ",edge[j].v);
}
printf("\n");
}
*/
for(i=1;i<=tot;i++)
{
if(dfn[i]==0)
{
dfs(i);
}
}
/*
printf("%d\n",cnt);
for(i=1;i<=tot;i++)
{
printf("%d ",belong[i]);
}
printf("\n");
*/
for(u=1;u<=tot;u++)
{
for(i=first[u];i!=-1;i=edge[i].next)
{
v=edge[i].v;
if(belong[u]!=belong[v])
{
degree[belong[u]]++;
}
}
}
minn=N;
for(i=1;i<=cnt;i++)
{
if(degree[i]==0)
{
minn=min(minn,sum[i]);
}
}
printf("%lld\n",minn);
return;
}
int main()
{
ll y;
int i,op,x,l,r;
scanf("%d",&n);
for(i=1;i<=n;i++)
{
scanf("%lld",&val[i]);
}
memset(root,0,sizeof(root));
memset(first,-1,sizeof(first));
memset(fmp,-1,sizeof(fmp));
for(i=1;i<=n;i++) f[i]=i;
gou=1,now=0,gg=n,num=0;
root[0]=build(1,n);
scanf("%d",&q);
for(i=1;i<=q;i++)
{
scanf("%d",&op);
if(op==0)
{
scanf("%d%lld",&x,&y);
gg++;
val[gg]=y;
f[x]=gg;
now++;
root[now]=update(root[now-1],x,1,n);
}
else
{
scanf("%d%d%d",&x,&l,&r);
solve(root[now],mp[f[x]],l,r,1,n);
}
}
tarjan();
return 0;
}
中等版
数据量放小了很多 直接缩点即可
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define N 0x3f3f3f3f3f3f3f3f
struct node
{
int v;
int next;
};
stack <int> stk;
node edge1[400010],edge2[400010];
ll pre[200010],sum[200010];
int first1[200010],first2[200010];
int f[200010],dfn[200010],low[200010],book[200010],belong[200010],degree[200010];
int n,num,cnt;
void addedge(node* edge,int* first,int u,int v)
{
edge[num].v=v;
edge[num].next=first[u];
first[u]=num++;
return;
}
void dfs(int cur)
{
int i,v;
stk.push(cur);
dfn[cur]=num,low[cur]=num,book[cur]=1;
num++;
for(i=first1[cur];i!=-1;i=edge1[i].next)
{
v=edge1[i].v;
if(!dfn[v])
{
dfs(v);
low[cur]=min(low[cur],low[v]);
}
else if(book[v])
{
low[cur]=min(low[cur],dfn[v]);
}
}
if(dfn[cur]==low[cur])
{
cnt++;
while(!stk.empty())
{
v=stk.top();
stk.pop();
book[v]=0;
belong[v]=cnt;
sum[cnt]+=pre[v];
if(cur==v) break;
}
}
return;
}
void tarjan()
{
int i,u,v;
while(!stk.empty()) stk.pop();
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
memset(book,0,sizeof(book));
memset(belong,0,sizeof(belong));
memset(sum,0,sizeof(sum));
num=1,cnt=0;
for(u=1;u<=n;u++)
{
if(!dfn[u]) dfs(u);
}
memset(degree,0,sizeof(degree));
for(u=1;u<=n;u++)
{
for(i=first1[u];i!=-1;i=edge1[i].next)
{
v=edge1[i].v;
if(belong[u]!=belong[v])
{
degree[belong[u]]++;
}
}
}
return;
}
int main()
{
ll val,ans;
int i,q,op,tar,l,r;
scanf("%d",&n);
for(i=1;i<=n;i++)
{
scanf("%lld",&pre[i]);
}
memset(first1,-1,sizeof(first1));
for(i=1;i<=n;i++) f[i]=i;
num=0;
scanf("%d",&q);
while(q--)
{
scanf("%d",&op);
if(op==0)
{
scanf("%d%lld",&tar,&val);
n++;
f[tar]=n;
pre[n]=val;
}
else
{
scanf("%d%d%d",&tar,&l,&r);
for(i=l;i<=r;i++)
{
if(i!=tar)
{
addedge(edge1,first1,f[tar],f[i]);
}
}
}
}
tarjan();
ans=N;
for(i=1;i<=cnt;i++)
{
if(degree[i]==0)
{
ans=min(ans,sum[i]);
}
}
printf("%lld\n",ans);
return 0;
}
简单版
队友写的
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll inf = 0x3f3f3f3f3f3f3f3f;
const int maxn = 1e5+5000;
int n,m;
vector<int> g[maxn];
int val[maxn], id[maxn],vis[maxn];
ll tmp_ans;
void dfs(int u) {
tmp_ans += val[u];
vis[u] = 1;
for(int i = 0; i < g[u].size(); ++i) {
int v = g[u][i];
if(vis[v]) continue;
dfs(v);
}
}
ll work(int x) {
memset(vis, 0, sizeof vis);
tmp_ans = 0;
dfs(x);
return tmp_ans;
}
int main()
{
scanf("%d", &n);
for(int i = 1; i <= n; ++i)
{
scanf("%d", &val[i]);
id[i] = i;
}
scanf("%d", &m);
int cnt = n;
for(int ii = 1; ii <= m; ++ii) {
int key; scanf("%d", &key);
if(key == 0) {
int x, y;
scanf("%d %d", &x, &y);
id[x] = ++cnt;
val[cnt] = y;
}
else {
int x, l, r;
scanf("%d %d %d", &x, &l, &r);
for(int i = l; i <= r; ++i) {
g[id[x]].push_back(id[i]);
}
}
}
ll ans = inf;
for(int i = 1; i <= cnt; ++i) {
ans = min(work(i), ans);
}
printf("%lld\n", ans);
return 0;
}