困难版
题意有些绕 这就不说了 一个点对一个连续区间内的所有点连一条权值相同的边 这个线性的过程可以用线段树来优化
但是这道题中每个位置上的元素会改变 这样只用线段树是无法维护的 需要用主席树来维护 这也没啥好说的 学了主席树其中道理自然明白 然后就是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; }