列表

详情


NC21601. 出题人的无向图

描述

出题人有一个n个点,m条边的无向图,点有属性ai和bi,以及一个神秘常数kk
有q组询问,每组询问给出正整数v,k和k个点
对于每个询问,在原图中删去(给定的k个点所在的连通块)和(属性ai大于v的点)  (只作用于这次询问) 
再删去与这些点相连的边(也只作用于这次询问)
那么剩下的图就有了一些联通块
对于每个联通块,定义其贡献为连通块中的不同的属性b数量(这个连通块中存在此属性b,且出现次数为kk的倍数)
每个询问输出此时所有联通块的贡献的最大值

输入描述

输入文件开始为3个正整数n,m,kk
然后两行,每行n个正整数。
第一行为每个点的属性a[i],
第二行为每个点的属性b[i]。
然后为m行,每行两个不相同的整数x,y表示m条边的端点(保证无重边,端点合法)
这之后为一个正整数q,表示询问个数。
接下来q行每行描述一个询问,
每行第一个数为V,第二个数为k,接下来k个数表示删去的点(不保证两两不同)

输出描述

输出文件共q行,每行一个整数,表示该次询问的答案。
若该次询问中所有点都被删掉,输出0

示例1

输入:

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

说明:

第一次询问,有1、3、5号点,它们之间有关联。
同时1、3、2三种属性各有一种,没有2的倍数个。
第二次询问,和第一问类似,由于3号点所在的连通块被坏了,没有剩下连通块。
第三次询问,v太小,删去了所有点。
第四次询问,有1、3、4、5,属性分别为1、3、2、2,属性2的有2个,所以答案为1。
第五次询问,所有点都没删去,属性分别为1、3、3、2、2,属性3、2各有两个,
所以答案为2。

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++(g++ 7.5.0) 解法, 执行用时: 775ms, 内存消耗: 90160K, 提交时间: 2022-11-16 18:28:42

#include<iostream>
#include<set>
#include<vector>
#include<map>
#include<algorithm>
using namespace std;

const int N=5e5+5;

int n,m,q,kk,p[N],ans[N],f[N],a[N],b[N],id[N];
multiset<int>Q;
vector<int>to[N],e[N];
map<int,int>S[N];
struct node{
    int a,b,w;
    bool operator <(node x){
        return w<x.w;
    }
}h[N];
struct Node{
    int v,k,id;
    bool operator <(Node x){
        return v<x.v;
    }
}t[N];
bool del[N];

int find(int x)
{
    if(x!=p[x]) p[x]=find(p[x]);
    return p[x];
}

void add(int x,int c)
{
    Q.erase(Q.find(f[x]));
    if(S[x][c]%kk==0&&S[x][c]>0) f[x]--;
    S[x][c]++;
    if(S[x][c]%kk==0) f[x]++;
    Q.insert(f[x]);
}

void merge(int l,int r)
{
    if(to[l].size()>to[r].size()) swap(l,r);
    p[l]=r;
    for(int i:to[l])
    {
        to[r].push_back(i);
        add(r,b[i]);
    }
    Q.erase(Q.find(f[l]));
}

bool cmp(int &x,int &y)
{
    return a[x]<a[y];
}

int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    
    cin>>n>>m>>kk;
    for(int i=1;i<=n;i++) cin>>a[i],id[i]=i;
    sort(id+1,id+1+n,cmp);
    for(int i=1;i<=n;i++) cin>>b[i];
    for(int i=1;i<=m;i++)
    {
        int l,r,w;
        cin>>l>>r;
        w=max(a[l],a[r]);
        h[i]={l,r,w};
    }
    sort(h+1,h+1+m);
    cin>>q;
    for(int i=1;i<=q;i++) 
    {
        int v,k,x;
        cin>>v>>k;
        t[i]={v,k,i};
        for(int j=1;j<=k;j++) cin>>x,e[i].push_back(x);
    }
    sort(t+1,t+1+q);
    for(int i=1;i<=n;i++) p[i]=i,to[i].push_back(i),Q.insert(0);
    int cnt1=1,cnt2=1;
    for(int i=1;i<=q;i++) 
    {
        int v=t[i].v,k=t[i].k;
        while(cnt1<=n&&a[id[cnt1]]<=v) 
        {
            int u=find(id[cnt1]);
            add(u,b[id[cnt1]]);
            cnt1++;
        }
        while(cnt2<=m&&h[cnt2].w<=v) 
        {
            int l=find(h[cnt2].a),r=find(h[cnt2].b);
            if(l!=r) merge(l,r);
            cnt2++;
        }
        for(int j:e[t[i].id])
        {
            int u=find(j);
            if(!del[u]) 
            {
                del[u]=1;
                Q.erase(Q.find(f[u]));
            }
        }
        if(Q.size()) ans[t[i].id]=*Q.rbegin();
        else ans[t[i].id]=0;
        for(int j:e[t[i].id])
        {
            int u=find(j);
            if(del[u]) 
            {
                del[u]=0;
                Q.insert(f[u]);
            }
        }
    }
    for(int i=1;i<=q;i++) cout<<ans[i]<<"\n";
    return 0;
}

C++14(g++5.4) 解法, 执行用时: 1427ms, 内存消耗: 81036K, 提交时间: 2019-01-20 20:29:16

#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e5+5;
const int maxq = 5e5+5;
int n, m, kk;
int a[maxn], b[maxn], a_id[maxn];
int fa[maxn], sz[maxn];
int cnt[maxn];
map<int, int> mp[maxn]; 
vector<int> G[maxn];
multiset<int>s;
struct qnode{
	int id;
	int v;
	vector<int>k;
	bool operator < (const qnode &rhs) const {
		return v < rhs.v;
	}
}query[maxq];
int ans[maxq];
bool in_map[maxn];
bool deleted[maxn];
int find(int x) {
	if (fa[x] == x)
		return x;
	else
		return fa[x] = find(fa[x]);
}
void combine(int x, int y) {
	if (sz[x] > sz[y])
		swap(x, y);
	sz[y] += sz[x];
	fa[x] = y;
	s.erase(s.find(cnt[x]));
	s.erase(s.find(cnt[y]));
	for (auto status : mp[x]) {
		int v_in_x = status.second;
		int v_in_y = mp[y][status.first];
		if (v_in_y)
			cnt[y] -= ((v_in_y)%kk == 0) ? 1 : 0;
		mp[y][status.first] += v_in_x;
		if ((v_in_x + v_in_y) % kk == 0)
			cnt[y]++;
	}
	s.insert(cnt[y]);
}

void M_insert(int id) {
	in_map[id] = true;
	s.insert(cnt[id]);
	for (int nxt : G[id]) {
		if (in_map[nxt] && find(nxt) != find(id)) {
			combine(find(nxt), find(id));
		}
	}
}
int main() {
	scanf("%d%d%d", &n, &m, &kk);
	for (int i = 1; i <= n; ++i)
		scanf("%d", a+i);
	for (int i = 1; i <= n; ++i)
		scanf("%d", b+i);
	int x, y;
	while (m--) {
		scanf("%d%d", &x, &y);
		G[x].push_back(y);
		G[y].push_back(x);
	}
	int numq;
	scanf("%d", &numq);
	int knum, kval;
	for (int i = 1; i <= numq; ++i) {
		scanf("%d%d", &query[i].v, &knum);
		while (knum--) {
			scanf("%d", &kval);
			query[i].k.push_back(kval);
		}
		query[i].id = i;
	}
	sort(query+1, query+1+numq);
	for (int i = 1; i <= n; ++i)
		a_id[i] = i;
	sort(a_id+1, a_id+1+n, [&](int x, int y){return a[x] < a[y];});
	for (int i = 1; i <= n; ++i) {
		fa[i] = i;
		sz[i] = 1;
		mp[i][b[i]] = 1;
		cnt[i] = (kk==1)?1:0;
	}
	s.insert(0);
	int cur = 0;
	for (int i = 1; i <= numq; ++i){
		while (cur < n && a[a_id[cur+1]] <= query[i].v) {
			cur++;
			M_insert(a_id[cur]);
		}
		for (auto p :query[i].k) {
			if (in_map[p] && !deleted[find(p)]) {
				s.erase(s.find(cnt[find(p)]));
				deleted[find(p)] = true;
			}
		}
		ans[query[i].id] = *(--s.end());
		for (auto p : query[i].k) {
			if (in_map[p] && deleted[find(p)]) {
				deleted[find(p)] = false;
				s.insert(cnt[find(p)]);
			}
		}
	}
	for (int i = 1; i <= numq; ++i) {
		printf("%d\n", ans[i]);
	}
	return 0;
}

C++11(clang++ 3.9) 解法, 执行用时: 1206ms, 内存消耗: 70776K, 提交时间: 2019-06-01 14:50:04

#include<bits/stdc++.h>
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define fi first
#define se second
typedef long long ll;
using namespace std;
const int mx = 2e5 + 10;
int n,m,K,a[mx],b[mx];
int ret[mx*3],fa[mx],cnt[mx];
multiset <int> st;
vector <int> g[mx];
map <int,int> mp[mx];
int find(int x){
	return x==fa[x]? x:fa[x]=find(fa[x]);
}
struct node{
	int p,v;
	bool operator < (node A)const{return v < A.v;}
}s[mx];
struct edge{
	int v,p;
	vector<int> r;
	bool operator < (edge A)const{return v < A.v;}
}e[mx*3];
void merge(int x,int y){
	x = find(x);
	y = find(y);
	if(x==y) return ;
	st.erase(st.find(cnt[x]));
	st.erase(st.find(cnt[y]));
	if(mp[x].size()<mp[y].size()) swap(x,y);
	fa[y] = x;
	for(auto it:mp[y]){
		if(mp[x][it.fi]&&mp[x][it.fi]%K==0) cnt[x]--;
		mp[x][it.fi] += it.se;
		if(mp[x][it.fi]%K==0) cnt[x]++;
	}
	st.insert(cnt[x]);
}
void add(int p){
	fa[p] = p;
	mp[p][b[p]] = 1;
	if(K==1) cnt[p] = 1;
	st.insert(cnt[p]);
	for(int v:g[p]) if(fa[v]){
		merge(p,v);
	}
}
int solve(int p,int x){
	while(p<=n&&s[p].v<=e[x].v) add(s[p++].p);
	int siz = e[x].r.size();
	set <int> s1;
	for(int i=0;i<siz;i++) if(fa[e[x].r[i]])
	s1.insert(find(e[x].r[i]));
	for(auto it:s1)
	st.erase(st.find(cnt[it]));
	if(st.empty()) ret[e[x].p] = 0;
	else ret[e[x].p] = *st.rbegin();
	for(auto it:s1) st.insert(cnt[it]);
	return p;
}
int main(){
 	scanf("%d%d%d",&n,&m,&K);
 	for(int i=1;i<=n;i++){
 		scanf("%d",a+i);
 		s[i].v = a[i],s[i].p = i; 
	}
	for(int i=1;i<=n;i++) scanf("%d",b+i);
	int u,v,q;
	while(m--){
		scanf("%d%d",&u,&v);
		g[u].push_back(v);
		g[v].push_back(u);
	}
	scanf("%d",&q);
	for(int i=1;i<=q;i++){
		scanf("%d",&e[i].v);
		e[i].p = i;
		scanf("%d",&u);
		for(int j=1;j<=u;j++){
			scanf("%d",&v);
			e[i].r.push_back(v);
		}
	}
	sort(s+1,s+1+n);
	sort(e+1,e+1+q);
	for(int i=1,p=1;i<=q;i++) 
	p = solve(p,i);
	for(int i=1;i<=q;i++) printf("%d\n",ret[i]);
    return 0;
}

上一题