COJ 1700:联通与次联通
题意:有N个人,M对关系,同时给出每个人的贡献c[i]。要求对于每一个人以及他认识的所有人,收入按照贡献由高到低不矛盾,求最小的总收入
思路:从最小贡献的人开始考虑。可以想到影响他收入的人只能是和他联通的人以及次联通的人,那他的收入就是这些人中比他贡献低的人的收入max+1
对于某人次联通的人来说,两者之间肯定有一个共同认识的人,由题意可以得出两者也会影响
一开始想到了从最小贡献的人开始考虑,但是不清楚次联通怎么处理。。
这里难的地方就在于如何快速找到某个点的联通和次联通的所有点中的最小值
这里还要注意一个地方就是相同贡献的要作为一组同时处理
因为从贡献最小的开始处理后,得到他的工资后就无用了,所以我们用他的工资来处理和他联通的点
这样做的话,该点的次联通就只需要查询公共点的cost就能够判断
注意代码中的cost不是表示工资,cost[i]=j表示的是第i个点以及其联通的点中最大工资为j
#include"cstdio" #include"queue" #include"cmath" #include"stack" #include"iostream" #include"algorithm" #include"cstring" #include"queue" #include"map" #include"set" #include"vector" #define LL long long #define mems(a,b) memset(a,b,sizeof(a)) #define ls pos<<1 #define rs pos<<1|1 #define max(a,b) (a)>(b)?(a):(b) using namespace std; const int N = 1e5+5;; const int MAXN = 200; const int INF = 0x3f3f3f3f; struct node{ int w,id; }c[N]; vector<int> G[N],vec; int cost[N],d[N],tmp[N]; LL ans; bool cmp(node a,node b){ return a.w<b.w; } void update(vector<int> &vec){ for(int i=0;i<vec.size();i++){ int u=vec[i]; int maxv=0; for(int j=0;j<G[u].size();j++){ int v=G[u][j]; //if(d[v]<=d[u]) maxv=max(maxv,cost[v]); } tmp[u]=maxv+1; //cout<<u<<' '<<tmp[u]<<endl; ans+=(LL)tmp[u]; } for(int i=0;i<vec.size();i++){ int u=vec[i]; cost[u]=tmp[u]; for(int j=0;j<G[u].size();j++){ int v=G[u][j]; //if(d[v]>=d[u]) cost[v]=cost[u]; } } vec.clear(); } int main(){ int n,m; //freopen("in.txt","r",stdin); while(~scanf("%d",&n)){ for(int i=1;i<=n;i++) G[i].clear(); mems(cost,0); for(int i=1;i<=n;i++){ scanf("%d",&d[i]); c[i].id=i; c[i].w=d[i]; } sort(c+1,c+n+1,cmp); scanf("%d",&m); for(int i=0;i<m;i++){ int a,b; scanf("%d%d",&a,&b); G[a].push_back(b); G[b].push_back(a); } vec.clear(); int k=1; ans=0; while(k<=n){ while(vec.empty()||d[c[k].id]==d[c[k-1].id]) vec.push_back(c[k++].id); update(vec); } printf("%lld\n",ans); } return 0; }