题意:
给你一个n个点,m条边的无向图,每一个点有两个属性ai,bi<=INT_MAX
有q个询问,每一个询问,一个边界v,和k个点c1..ck
对于每一次询问,进行操作(此操作只作用于本次询问)
先将ai>v的点全部删除,包括连接这些点的边
在把剩下的图中编号为c1..ck这些点各自对应的连通块删除
再对最后剩下的图中的连通块定义其权值:一个连通块的权值是
连通块中的不同的属性b数量(这个连通块中存在此属性b,且出现次数为kk的倍数)
每个询问输出此时所有联通块的权值的最大值
解析:
这道题原本的题面对于删除k个点对应得连通块这一个操作和删除ai>v的点的操作先后性根本没有讲...
导致我一开始以为,先删那k个连通块再删ai>v的点。...后来看了别人的代码,发现顺序刚好相反.....
做法的大致思路就是
边先保存起来,每一个点都看作一个连通块
然后离线询问,将询问按照v值从小到大排序
一开始是一个空图,对于每一个询问,我们把ai<=v的点全部加入到图中
,同时把这些点连接的边也一并加入到图中。
这里的核心步骤就是加点。
例如当加入新的点x,我们要x连接的边(同时这个边的另外一个节点已经在图中)都加入到图中
,当加入边的过程中,我们都同时要进行合并连通块的操作(启发式合并,size小的并入siz大的,时间优化)——
把siz小的连通块的各个点的值,加入到siz大的连通块的mp中,同时不断更新siz大的连通块的权值
因为边的加入就会产生连通块。
并且在这些步骤的同时我们也还要一直更新连通块的权值(旧的权值删除,新的权值加入),并且维护这些里面的最大值
ps:对于每一个询问,我们维护的应该是ai<=这个询问的v的所有点组成的各个连通块的权值的最大值
(千万不要漏点,我一开始用边插入的时候,就是因为这个地方错的)
这里我用的是线段树来维护的,叶子节点表示的是编号为x的连通块的权值。
我看其他大佬的代码也有用堆来维护的,用的是multiset,因为这里的堆需要用到定值删除的操作(给定一个值,在堆中删除他)
用堆维护很简单,更新的时候就把原来的那个值从堆中删除,然后再把新的值插入进去。
删除k个连通块时,也只需要把这k个连通块对应的值从堆中删除,求最大值,然后再把删除的值插入进去就可以了。
用线段树的话,我是先将这k个点,按照他们连通块的编号排序,然后按照这些需要删除的连通块的序号把
[1,n]分成一段段区间,然后区间查询最大值,然后再取最大值的最大值。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
using namespace std;
#define mk make_pair
typedef long long ll;
typedef pair<int,int> PII;
const int N = 2e5+10;
const int M = 5e5+10;
typedef struct point
{
int first;
int second;
int id;
friend bool operator<(point a,point b)
{
return a.first<b.first;
}
}point;
point node[N];
int n,m,kk;
int a[N],sz[N];
int vis[N];
vector<int> edge[N];
int fa[N];
int k[N];
int Btree[N*4];
map<int,int> mp[N];
int ans[M],val[N];
typedef struct query
{
int v;
int l,r;
int id;
}query;
query mq[M];
//set<int> father;
int findfa(int x)
{
if(x==fa[x]) return x;
int nex=fa[x];
fa[x]=findfa(nex);
return fa[x];
}
bool cmp(query a,query b)
{
return a.v<b.v;
}
bool cmpk(int a,int b)
{
return findfa(a)<findfa(b);
}
void build(int l,int r,int root) //l,r表示他们在stu中的下标,root表示他们在线段树中的坐标
{
if(l>r)return;
if(l==r)
{
Btree[root]=0;
return;
}
int mid=(l+r)/2;
build(l,mid,root*2);
build(mid+1,r,root*2+1);
Btree[root]=max(Btree[root*2],Btree[root*2+1]);
}
void updateone(int root,int l,int r,int index,int val)
{
if(l>r)return;
if(l==r)
{
if(l==index)
Btree[root]+=val;
return;
}
int mid=(l+r)/2;
if(index<=mid)
updateone(root*2,l,mid,index,val);
else
updateone(root*2+1,mid+1,r,index,val);
Btree[root]=max(Btree[2*root],Btree[2*root+1]);
}
int query_max(int root,int s1,int e1,int s2,int e2)
{
if(e1<s2||s1>e2)
return 0;
if(s1>e1)return 0;
if(s1>=s2&&e1<=e2)
{
return Btree[root];
}
//pushDown(root);
int mid=(s1+e1)/2;
int lm,rm;
lm=rm=0;
if(s2<=mid)
lm=query_max(root*2,s1,mid,s2,e2);
if(mid+1<=e2)
rm=query_max(root*2+1,mid+1,e1,s2,e2);
return max(lm,rm);
}
void combine(int u,int v)
{
if(sz[u]<sz[v]) swap(u,v); //启发式合并
sz[u]+=sz[v];
sz[v]=0;
fa[v]=u;
int past=val[u];
for(auto s:mp[v])
{
int su=0;
if(mp[u].count(s.first))
{
su=mp[u][s.first];
if(!su) val[u]-=1;
}
su=(su+s.second)%kk;
if(!su) val[u]+=1;
mp[u][s.first]=su;
}
updateone(1,1,n,u,val[u]-past);
updateone(1,1,n,v,-val[v]);
val[v]=0;
}
void cal(int x)
{
vis[x]=1;
updateone(1,1,n,x,val[x]);
for(auto s:edge[x])
{
if(vis[s]){
int fx=findfa(x);
int fy=findfa(s);
if(fx!=fy) combine(fx,fy);
}
}
}
int main()
{
scanf("%d%d%d",&n,&m,&kk);
for(int i=1;i<=n;i++)
{
scanf("%d",&node[i].first);
fa[i]=i;
node[i].id=i;
vis[i]=0;
sz[i]=1;
}
for(int i=1;i<=n;i++)
{
scanf("%d",&node[i].second);
mp[i][node[i].second]=1%kk;
val[i]=(kk==1?1:0);
}
sort(node+1,node+1+n);
for(int i=1;i<=n;i++) a[i]=node[i].first;
for(int i=1;i<=m;i++)
{
int u,v;
scanf("%d%d",&u,&v);
edge[u].push_back(v);
edge[v].push_back(u);
}
int sz=n;
build(1,sz,1);
int q,cnt;
cnt=0;
scanf("%d",&q);
for(int i=1;i<=q;i++)
{
int tmp;
scanf("%d%d",&mq[i].v,&tmp);
mq[i].l=cnt;
mq[i].r=cnt+tmp;
mq[i].id=i;
while(cnt<mq[i].r)
{
scanf("%d",&k[cnt]);
cnt++;
}
}
sort(mq+1,mq+1+q,cmp);
int pre=0;
for(int i=1;i<=q;i++)
{
int nxt=upper_bound(a+1,a+1+n,mq[i].v)-a;
for(int j=pre+1;j<nxt;j++)
{
pre=j;
cal(node[j].id);
}
sort(k+mq[i].l,k+mq[i].r,cmpk);
int past=1;
int res=0;
for(int j=mq[i].l;j<mq[i].r;j++)
{
int w=findfa(k[j]);
if(past<w)
{
res=max(res,query_max(1,1,sz,past,w-1));
}
past=w+1;
}
if(past<sz+1)
{
res=max(res,query_max(1,1,sz,past,sz));
}
ans[mq[i].id]=res;
}
for(int i=1;i<=q;i++)
{
printf("%d\n",ans[i]);
}
}
用multiset的
#include <bits/stdc++.h>
using namespace std;
#define mk make_pair
typedef long long ll;
typedef pair<int,int> PII;
const int N = 2e5+10;
const int M = 5e5+10;
typedef struct point
{
int first;
int second;
int id;
friend bool operator<(point a,point b)
{
return a.first<b.first;
}
}point;
point node[N];
int n,m,kk;
int a[N],sz[N];
int vis[N];
vector<int> edge[N];
int fa[N];
int k[N];
bool del[N];
multiset<int> p;
map<int,int> mp[N];
int ans[M],val[N];
typedef struct query
{
int v;
int l,r;
int id;
}query;
query mq[M];
//set<int> father;
int findfa(int x)
{
if(x==fa[x]) return x;
int nex=fa[x];
fa[x]=findfa(nex);
return fa[x];
}
bool cmp(query a,query b)
{
return a.v<b.v;
}
bool cmpk(int a,int b)
{
return findfa(a)<findfa(b);
}
void combine(int u,int v)
{
if(sz[u]<sz[v]) swap(u,v); //启发式合并
sz[u]+=sz[v];
sz[v]=0;
fa[v]=u;
p.erase(p.find(val[u]));
p.erase(p.find(val[v]));
for(auto s:mp[v])
{
int su=0;
if(mp[u].count(s.first))
{
su=mp[u][s.first];
if(!su) val[u]-=1;
}
su=(su+s.second)%kk;
if(!su) val[u]+=1;
mp[u][s.first]=su;
}
p.insert(val[u]);
val[v]=0;
}
void cal(int x)
{
vis[x]=1;
p.insert(val[x]);
for(auto s:edge[x])
{
if(vis[s]){
int fx=findfa(x);
int fy=findfa(s);
if(fx!=fy) combine(fx,fy);
}
}
}
int main()
{
scanf("%d%d%d",&n,&m,&kk);
for(int i=1;i<=n;i++)
{
scanf("%d",&node[i].first);
fa[i]=i;
node[i].id=i;
vis[i]=0;
sz[i]=1;
del[i]=false;
}
for(int i=1;i<=n;i++)
{
scanf("%d",&node[i].second);
mp[i][node[i].second]=1%kk;
val[i]=(kk==1?1:0);
}
sort(node+1,node+1+n);
for(int i=1;i<=n;i++) a[i]=node[i].first;
for(int i=1;i<=m;i++)
{
int u,v;
scanf("%d%d",&u,&v);
edge[u].push_back(v);
edge[v].push_back(u);
}
int q,cnt;
cnt=0;
scanf("%d",&q);
for(int i=1;i<=q;i++)
{
int tmp;
scanf("%d%d",&mq[i].v,&tmp);
mq[i].l=cnt;
mq[i].r=cnt+tmp;
mq[i].id=i;
while(cnt<mq[i].r)
{
scanf("%d",&k[cnt]);
cnt++;
}
}
sort(mq+1,mq+1+q,cmp);
int pre=0;
for(int i=1;i<=q;i++)
{
int nxt=upper_bound(a+1,a+1+n,mq[i].v)-a;
for(int j=pre+1;j<nxt;j++)
{
pre=j;
cal(node[j].id);
}
for(int j=mq[i].l;j<mq[i].r;j++)
{
int w=findfa(k[j]);
if(vis[k[j]]&&!del[w])
{
p.erase(p.find(val[w]));
del[w]=true;
}
}
if(p.empty()) ans[mq[i].id]=0;
else ans[mq[i].id]=*(p.rbegin());
for(int j=mq[i].l;j<mq[i].r;j++)
{
int w=findfa(k[j]);
if(del[w])
{
p.insert(val[findfa(w)]);
del[w]=false;
}
}
}
for(int i=1;i<=q;i++)
{
printf("%d\n",ans[i]);
}
}