【2018/08/21测试T3】【SDOJ 3761】复杂的电路系统

【题目】

题目描述:

有一个复杂的电路系统,有 n 个节点,m 条导线,电流可以从导线任意一端流向另一端。 每个节点上有个电路元器件,每个电路元器件有启动电压和功能属性。只有电压大于等于启动电压,才能启动电路元器件。只有一条导线两端节点上的电路元器件都启动,这条导线才会有电流经过(这同时意味着这两个电路元器件有关联,关联有传递性)。

由于机房断电的复杂性,如果一个极大的两两有关联的电路元器件集合中,某种功能属性的元器件存在且个数恰好为一个神秘常数 kk 的倍数,那么视为这个元器件集合有这种功能属性。

由于机房断电的复杂性,管理人员只能先切断了电源,再给出一定的启动电压,让某些元器件启动。很显然,极大的两两有关联的电路元器件组成了一个集合 A,所有的可以启动的元器件组成了若干个这样的集合。而一个集合 A 的功能值是指 A 集合不同功能属性的数量。

为了让功能恢复地尽可能地快,管理人员希望知道在这个启动电压下,在所有可以启动的 A 中,最大的功能值。

本来这非常简单,可是管理人员不慎踩坏了一些电路元器件,这不仅使该元器件报废,还使得在该电压下所有与该元器件有关联的所有元器件报废了。

管理员无能为力,只好思考新的问题,管理员希望知道在这个启动电压下,在所有没有报废的 A 中,最大的功能值。

输入格式:

输入文件开始为三个正整数 n , m , kk

然后两行,每行 n 个整数。

第一行为每个节点的电路元器件的启动电压 a[ i ],第二行为每个节点的电路元器件的功能属性 b[ i ]。

然后为 m 行,每行两个不相同的整数 x,y 表示 m 条边的端点(保证无重边,端点合法)

这之后为一个正整数 q,表示询问个数。接下来 q 行每行描述一个询问,

每行第一个数为启动电压 V,第二个数为管理员踩坏元器件的个数 k,接下来 k 个数表示踩坏的元器件所在节点(不保证两两不同)

输出格式:

输出文件共 q 行,每行一个整数,表示该次询问的答案。

若该次询问中没有没有报废的 A 请输出 0 

样例数据:

输入

5 4 2
3 7 2 5 4
1 3 3 2 2
1 3
1 2
3 4
3 5
5
4 0
4 1 3
1 0
5 0
10 0

输出

0
0
0
1
2

备注:

【样例解释】

第一次询问,启动电压为 4,启动了 1、3、5 号点,它们之间有关联。
同时 1、3、2 三种功能属性各有一种,没有 2 的倍数个。
第二次询问,和第一问类似,由于 3 号点所在的集合被踩坏了,没有可以启动的元器件集合。
第三次询问,启动电压太低,启动不了任何点。
第四次询问,启动了 1、3、4、5,功能属性分别为 1、3、2、2,2 功能属性的有 2 个,所以答案为 1。
第五次询问,启动了所有点,功能属性分别为 1、3、3、2、2,3、2 功能属性各有两个,所以答案为 2。

【数据特征】

 

【分析】

这道题我就先只发标程了,我自己还没做出来

 

【代码】

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
int n,m,i,j,K,a[N],b[N],q,ans[N],fa[N],have[N],BAN[N],mx[N];
struct edge{int x,y,h;}e[N];
struct ask{int h,num,id;}Q[N];
struct node{int h,id;}p[N];
inline bool cmp1(edge a,edge b){return a.h<b.h;}
inline bool cmp2(ask a,ask b){return a.h<b.h;}
inline bool cmp3(node a,node b){return a.h<b.h;}
vector<int> ban[N];
set<int> col[N];
map<int,int> COL[N];
priority_queue<pair<int,int> > que;
inline int find(int x)
{
	if(fa[x]==x)  return x;
	return fa[x]=find(fa[x]);
}
inline void merge(int x,int y){
	int fx=find(x);
	int fy=find(y);
	if(fx==fy)  return;
	if(col[fx].size()<col[fy].size())swap(fx,fy);
	for(set<int>::iterator it=col[fy].begin();it!=col[fy].end();++it)
		col[fx].insert(*it);
	for(map<int,int>::iterator it=COL[fy].begin();it!=COL[fy].end();++it){
		pair<int,int> tmp=*it;int now=(COL[fx][tmp.first]+(tmp.second))%K;
		if(now==0){
			map<int,int>::iterator hhh=COL[fx].find(tmp.first);
			if(hhh!=COL[fx].end())COL[fx].erase(hhh);
		}else COL[fx][tmp.first]=now;
	}
	have[fy]=0;fa[fy]=fx;
	mx[fx]=col[fx].size()-COL[fx].size();
	que.push(make_pair(mx[fx],fx));
	col[fy].clear();
}
pair<int,int> tmp[N];
int topt;
inline void calc(int x)
{
	map<int,int> in;in.clear();
	if(que.empty()){ans[x]=0;return;}
	for(int i=0;i<ban[x].size();i++)BAN[find(ban[x][i])]=1;
	topt=0;int TOT=0;
	while(BAN[que.top().second]||!have[que.top().second]||mx[que.top().second]!=que.top().first)
	{
		tmp[++topt]=que.top(),que.pop();TOT++;
		if(que.empty())break;
	}
	if(!que.empty())ans[x]=que.top().first;else ans[x]=0;
	int tot=0;
	for(int i=1;i<=topt;i++)
	if(have[tmp[i].second]&&tmp[i].first==mx[tmp[i].second]&&!in[tmp[i].second])
		que.push(tmp[i]),tot++,in[tmp[i].second]=1;
	for(int i=0;i<ban[x].size();i++)BAN[find(ban[x][i])]=0;
}
inline int Read(){
    int x=0,f=1;char c=getchar();
    while(c>'9'||c<'0') {if(c=='-') f=-1;c=getchar();}
    while(c>='0'&&c<='9') {x=x*10+c-'0'; c=getchar();}
    return x*f;
}
int main(){
//	freopen("effect.in","r",stdin);
//	freopen("effect.out","w",stdout);
	scanf("%d%d%d",&n,&m,&K);
	for(i=1;i<=n;i++)a[i]=Read(),p[i].id=i,p[i].h=a[i];sort(p+1,p+1+n,cmp3);
	for(i=1;i<=n;i++)b[i]=Read();
	for(i=1;i<=m;i++)e[i].x=Read(),e[i].y=Read(),e[i].h=max(a[e[i].x],a[e[i].y]);
	sort(e+1,e+1+m,cmp1);
	q=Read();
	for(i=1;i<=q;i++){
		Q[i].h=Read(),Q[i].num=Read();Q[i].id=i;int x;
		for(j=1;j<=Q[i].num;j++)x=Read(),ban[i].push_back(x);
	}
	sort(Q+1,Q+1+q,cmp2);
	for(i=1;i<=n;i++)fa[i]=i,have[i]=i,mx[i]=1;
	int now=1,now1=1;
	for(i=1;i<=q;i++){
		while(p[now1].h<=Q[i].h&&now1<=n){
			que.push(make_pair(1,p[now1].id));
			col[p[now1].id].insert(b[p[now1].id]);
			if(K!=1)COL[p[now1].id][b[p[now1].id]]++;
			now1++;
		}
		while(e[now].h<=Q[i].h&&now<=m)merge(e[now].x,e[now].y),now++;
		calc(Q[i].id);
	}
	for(i=1;i<=q;++i)
	  printf("%d\n",ans[i]);
//	fclose(stdin);
//	fclose(stdout);
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值