【题目】
题目描述:
有一个复杂的电路系统,有 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;
}