是个树状数组好题,但是我对建立多个树状数组并不是太了解写法,所以自己手写一下.
题目给定n个点,以及他们代表的数,然后给你m条边,然后支持两种操作,1是修改,2是查询.修改是把u节点的值改成x.查询是查询与u节点相邻点的mex.
思路:思路很清晰,考虑每个节点连接sqrt(m)的数量不可能超过sqrt(m)个,我们将点分为重点,轻点.重点就是超过sqrt(m)个的点,轻点就是没超过sqrt(m)的点.然后对于重点我们二分树状数组解决,对于轻点我们直接暴力求解,此外对于修改操作,对于其连接点是重点,我们要对其连接点的树状数组进行单点修改,且改变它本身的权值,对于轻点来说直接改变自己的权值即可.
#include <bits/stdc++.h>
#define debug cout<<"***"
using namespace std;
const int N=3e5+5;
vector<int>v[N],cnt[N],tree[N],G[N];
int zero[N],vis[N],w[N];
inline int lowbit(int x)
{
return x&(-x);
}
inline void add(int pos,int val,int id)
{
while(pos<G[id].size()+5)
{
tree[id][pos]+=val;
pos+=lowbit(pos);
}
}
inline int get_sum(int pos,int id)
{
int res=0;
while(pos)
{
res+=tree[id][pos];
pos-=lowbit(pos);
}
return res;
}
void change(int u,int x)
{
if(!w[u]) for(auto i:v[u]) zero[i]--;
else
{
for(auto i:v[u])
{
if(w[u]>G[i].size())
continue;
cnt[i][w[u]]--;
if(!cnt[i][w[u]]) add(w[u],-1,i);
}
}
if(!x)
{
for(auto i:v[u]) zero[i]++;
w[u]=x;
return;
}
for(auto i:v[u])
{
if(x>G[i].size()) continue;
cnt[i][x]++;
if(cnt[i][x]==1) add(x,1,i);
}
w[u]=x;
}
int query1(int u)
{
for(int i=0;i<=G[u].size();i++) vis[i]=0;
for(int i=0;i<G[u].size();i++)
{
int to=G[u][i];
if(w[to]>G[u].size()) continue;
vis[w[to]]++;
}
for(int i=0;i<=v[u].size();i++)
{
if(!vis[i]) return i;
}
}//暴力
int query2(int u)
{
if(!zero[u]) return 0;
int l=1,r=G[u].size(),res=G[u].size();
while(l<=r)
{
int mid=l+r>>1;
if(get_sum(mid,u)<mid) r=mid-1,res=mid;
else l=mid+1;
}
return res;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int n,m;
scanf("%d%d",&n,&m);
int qf=sqrt(m);
for(int i=1;i<=n;i++)
{
scanf("%d",&w[i]);
}
for(int i=1;i<=m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
G[x].push_back(y);
G[y].push_back(x);
//v[x].push_back(y);
//v[y].push_back(x);
}
for(int i=1;i<=n;i++) {
for(int j=0;j<G[i].size();j++) {
int nx=G[i][j];
if(G[nx].size()>=qf) v[i].push_back(nx);
}
}
for(int i=1;i<=n;i++)
{
if(G[i].size()>=qf)
{
tree[i].resize(G[i].size()+10);
cnt[i].resize(G[i].size()+10);
for(int j=0;j<=G[i].size();j++) tree[i][j]=cnt[i][j]=0;
for(int j=0;j<G[i].size();j++)
{
int to=G[i][j];
if(w[to]>G[i].size()) continue;
if(!w[to]) {zero[i]++;continue;}
cnt[i][w[to]]++;
if(cnt[i][w[to]]==1) add(w[to],1,i);
}
}
}
int Q;
scanf("%d",&Q);
while(Q--)
{
int a,b,c;
scanf("%d",&a);
if(a==1)
{
scanf("%d%d",&b,&c);
change(b,c);
}
else
{
scanf("%d",&b);
if(G[b].size()<=qf)
{
printf("%d\n",query1(b));
}
else printf("%d\n",query2(b));
}
}
for(int i=1;i<=n;i++) v[i].clear(),zero[i]=0,G[i].clear();
}
return 0;
}
京公网安备 11010502036488号