描述
有一个复杂的电路系统, 有 n 个节点, m 条导线,电流可以从导线任意一端流向另一端。 每个节点上有1个电路元器件,每个电路元器件有启动电压和功能属性。只有电压大于等于启动电压,才能启动电路元器件。只有一条导线两端节点上的电路元器件都启动,这条导线才会有电流经过(这同时意味着这两个电路元器件有关联,关联有传递性)。
由于机房断电的复杂性,如果一个极大的两两有关联的电路元器件集合中,某种功能属性的元器件存在且个数恰好为一个神秘常数 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(
的吐槽:不就是全部报废的情况吗,说人话好不好QAQ)。
样例输入
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。
数据范围及特征
测试点编号 | n | m | kk | q | ∑k | 特殊性质 |
---|---|---|---|---|---|---|
1,2,3,4,5,6 | <=100 | <=1000 | 无 | <=10000 | 无 | 无 |
7,8 | <=1000 | <=50000 | 无 | 无 | =0 | 无 |
9,10 | 无 | 无 | 无 | 无 | =0 | 无 |
11,12 | <=100 | 无 | =1 | 无 | 无 | 无 |
13,14 | 无 | 无 | =1 | 无 | 无 | 无 |
15 | 无 | 无 | 无 | 无 | 无 | 一条链 |
16,17 | 无 | 无 | 无 | 无 | 无 | 一棵树 |
18 | <=50000 | 无 | 无 | 无 | 无 | 无 |
19,20 | 无 | 无 | 无 | 无 | 无 | 无 |
(手打表格我容易吗我)
对于所有数据:
,
,
,
,
_
解析:
如果您觉得写可持久化并查集能过这道题请自便(没试过)。
考虑离线处理。
将所有询问排个序,按启动电压从小到大。
那么随着电压的逐渐增大,不同集合的元件会逐渐合并为一个集合(显而易见的并查集,合并采用启发式合并,减小复杂度),我们只在根节点处保留该集合的信息,查询也只查询根节点。
对于边,要使这条边能够加入的电压必须大于边的两端元器件中启动电压较大的那一个才行,那么边权设置为较大的启动电压,排序。
对于节点,考虑一些鬼畜的方式可能会使得这时候的答案真的是只有一个能够启动的情况,将节点按权值排序,初始答案为1,加入优先队列中去。
合并的时候如何更新该根节点的答案?就是该节点拥有的权值数量减去不为 倍数的数量。
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc getchar
#define pc putchar
#define cs const
#define st static
inline
ll getint(){
st ll num;
st char c;
for(c=gc();!isdigit(c);c=gc());
for(num=0;isdigit(c);c=gc())num=(num<<1)+(num<<3)+(c^48);
return num;
}
inline
void outint(ll a){
st char ch[23];
if(a==0)pc('0');
while(a)ch[++ch[0]]=(a-a/10*10)^48,a/=10;
while(ch[0])pc(ch[ch[0]--]);
}
inline
void swap(int &x,int &y){
x^=y;
y^=x;
x^=y;
}
#define mp make_pair
#define pii pair<int,int>
#define pb push_back
cs int N=200000;
cs int M=500000;
int n,m;
int b[N+2],T,ans[N+2],fa[N+2];
bool isroot[N+2];
int Ban[N+2],energy[N+2],kk;
struct edge{
int u,v,h;
bool operator<(cs edge &b)cs{
return h<b.h;
}
}e[M+3];
struct query{
int h,id;
bool operator<(cs query &b)cs{
return h<b.h;
}
}Q[N+2];
struct node{
int h,id;
bool operator<(cs node &b)cs{
return h<b.h;
}
}a[N+2];
vector<int> ban[N+2];
set<int> col[N+2];
map<int,int> COL[N+2];
priority_queue<pii ,vector<pii > ,less<pii > > q;
inline
int getfa(int x){
while(x!=fa[x])x=fa[x]=fa[fa[x]];
return x;
}
inline
void merge(int x,int y){
x=getfa(x),y=getfa(y);
if(x==y)return ;
if(col[x].size()<col[y].size())swap(x,y);
for(set<int>::iterator it=col[y].begin();it!=col[y].end();++it){
col[x].insert(*it);
}
for(map<int,int>::iterator it=COL[y].begin();it!=COL[y].end();++it){
pii tmp=*it;
int now=(COL[x][tmp.first]+tmp.second)%kk;
if(now==0){
map<int,int>::iterator del=COL[x].find(tmp.first);
if(del!=COL[x].end())COL[x].erase(del);
}
else COL[x][tmp.first]=now;
}
isroot[y]=0;
fa[y]=x;
energy[x]=col[x].size()-COL[x].size();
q.push(mp(energy[x],x));
col[y].clear();
}
inline
void calc(int id){
map<int,bool> inq;
stack<pii> tmp;
if(q.empty())return ;
for(int re i=0;i<ban[id].size();++i)Ban[getfa(ban[id][i])]=true;
while(!q.empty()&&(Ban[q.top().second]||!isroot[q.top().second]||energy[q.top().second]!=q.top().first))
tmp.push(q.top()),q.pop();
if(!q.empty())ans[id]=q.top().first;
while(!tmp.empty()){
if(isroot[tmp.top().second]&&tmp.top().first==energy[tmp.top().second]&&!inq[tmp.top().second])
q.push(tmp.top()),inq[tmp.top().second]=true;
tmp.pop();
}
for(int re i=0;i<ban[id].size();++i)Ban[getfa(ban[id][i])]=false;
}
int main(){
n=getint();
m=getint();
kk=getint();
for(int re i=1;i<=n;++i)
a[i].h=getint(),a[i].id=i;
for(int re i=1;i<=n;++i)
b[i]=getint(),fa[i]=i,isroot[i]=true,energy[i]=1;
for(int re i=1;i<=m;++i)
e[i].u=getint(),e[i].v=getint(),e[i].h=max(a[e[i].u].h,a[e[i].v].h);
sort(a+1,a+n+1);
sort(e+1,e+m+1);
T=getint();
for(int re i=1;i<=T;++i){
Q[i].h=getint();
int num=getint();
Q[i].id=i;
for(int re j=1;j<=num;++j){
int u=getint();
ban[i].pb(u);
}
}
sort(Q+1,Q+T+1);
int vcnt=1;
int ecnt=1;
for(int re i=1;i<=T;++i){
while(a[vcnt].h<=Q[i].h&&vcnt<=n){
q.push(mp(1,a[vcnt].id));
col[a[vcnt].id].insert(b[a[vcnt].id]);
if(kk!=1)++COL[a[vcnt].id][b[a[vcnt].id]];
++vcnt;
}
while(e[ecnt].h<=Q[i].h&&ecnt<=m)merge(e[ecnt].u,e[ecnt].v),++ecnt;
calc(Q[i].id);
}
for(int re i=1;i<=T;++i)outint(ans[i]),pc('\n');
return 0;
}