对每个点定义两个值:val,sum,val记录自己的特征值,sum记录周边所有点特征值的和。
把所有的节点分成两类,重点(度数>=sqrt(m)),轻点(度数<sqrt(m))。
更新:
轻点:更新自己的val,同时更新所有的邻点的sum值
重点:更新自己的val,同时只更新相邻重点的sum值(所以重点不需要连边到轻点)
查询:
轻点:暴力加上所有相邻点的val值。
重点:直接输出自己的sum值。
性质:
与重点相邻的重点不超过sqrt(m)个。
与轻点相邻的所有点不超过sqrt(m)个。
#include<cstdio>
#include<cstring>
#include<vector>
#include<cmath>
using namespace std;
#define N 2300010
#define ll long long
const int maxn=100005;
struct Edge
{
int u,v;
Edge(int u=0,int v=0):u(u),v(v){};
};
vector<Edge>edge;
vector<int>G[maxn];
int du[maxn],val[maxn];
ll sum[maxn],cnt;
int main(){
int T;
int u,v,n,m,q,k;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
edge.clear();
k=(int)sqrt(m+0.5);
for(int i=0;i<=n;i++)
{
du[i]=0;
val[i]=0;
sum[i]=0;
G[i].clear();
}
for(int i=0;i<m;i++)
{
scanf("%d%d",&u,&v);
edge.push_back(Edge(u,v));
du[u]++;
du[v]++;
}
for(int i=0;i<edge.size();i++)
{
u=edge[i].u;
v=edge[i].v;
if(du[u]>=k&&du[v]>=k)
{
G[u].push_back(v);
G[v].push_back(u);
}
if(du[u]<k) G[u].push_back(v);
if(du[v]<k) G[v].push_back(u);
}
scanf("%d",&q);
while(q--)
{
int cmd,x,y;
scanf("%d",&cmd);
if(cmd==1)
{
scanf("%d",&x);
cnt=0;
if(du[x]<k)
{
for(int i=0;i<G[x].size();i++)
{
cnt+=val[G[x][i]];
}
}
else
{
cnt=sum[x];
}
printf("%lld\n",cnt);
}
else
{
scanf("%d%d",&x,&y);
val[x]+=y;
for(int i=0;i<G[x].size();i++)
{
sum[G[x][i]]+=y;
}
}
}
}
return 0;
}