2018.08.21 【校内模拟】T3 复杂的电路系统 Effect(并查集启发式合并)(离线处理)(堆)

版权声明:转载请声明出处,谢谢配合。 https://blog.csdn.net/zxyoi_dreamer/article/details/81915382

描述

有一个复杂的电路系统, 有 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( z x y o i 的吐槽:不就是全部报废的情况吗,说人话好不好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 <= n <= 200000 , 1 <= m <= m i n ( ( n ( n 1 ) ) / 2 , 500000 ) , 1 <= q <= 200000
1 <= k k <= n , k <= 200000 , 1 <= a i <= b i <= I N T _ M A X


解析:

z x y o i 还要肝网络流。。。

什么时候他想起了这篇博文就来更新一下吧。。。

(好多 S T L …)


代码(已过,但是还有优化空间,改天重写):

#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;
}

猜你喜欢

转载自blog.csdn.net/zxyoi_dreamer/article/details/81915382