版权声明:本人蒟蒻,如有大佬转发,感激不尽,带上我的博客链接即可。 https://blog.csdn.net/qq_36300700/article/details/81558537
借鉴了一位的大佬的思路:https://www.cnblogs.com/HDUjackyan/p/8996172.html
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4858
思路:图的分块。设点i的点权为val[i],与点i相邻的项目的能量值之和为sum[i]。将图中的点分为重点和轻点,重点是那些边的度数超过sqrt(m)(该值可以自己规定)的点,除了重点剩下的点都是轻点。对于构图,重点只和重点建边,轻点可以和所有点建边。每次更新,对于重点i和轻点来说来说都是更新自己的val[i]和相邻点的sum[i]。而对于查询操作来说,重点直接输出sum[i],而轻点则采用暴力做法:遍历其每一个相邻点,答案累加上相邻的val[i]。采用的思想是分摊复杂度的思想
ac代码:
#include <iostream>
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <stdlib.h>
#include <algorithm>
#include <queue>
#include <vector>
using namespace std;
const int maxn =100000+50;
#define ll long long
vector<int>mp[maxn],G[maxn];
ll val[maxn],sum[maxn],deg[maxn],vis[maxn];
ll T,n,m,Q,cmd,block;
void init()
{
for(int i=0; i<=n; i++)
{
G[i].clear();
mp[i].clear();
}
memset(sum,0,sizeof(sum));
memset(deg,0,sizeof(deg));
memset(val,0,sizeof(val));
memset(vis,0,sizeof(vis));
}
int main()
{
scanf("%lld",&T) ;
while(T--)
{
init();
scanf("%lld %lld",&n,&m);
block=sqrt(m);
ll a,b;
for(int i=0; i<m; i++)
{
scanf("%lld %lld",&a,&b);
deg[a]++;
deg[b]++;
mp[a].push_back(b);
}
for(int i=1; i<=n ;i++)
{
if(deg[i]>block)
vis[i]=1;
}
for(int u=1; u<=n; u++)
{
for(int j=0; j<mp[u].size(); j++)
{
int v=mp[u][j];
if(vis[u])
{
if(vis[v])
{
G[u].push_back(v);
G[v].push_back(u);
}
else
{
G[v].push_back(u);
}
}
else
{
if(vis[v])
{
G[u].push_back(v);
}
else
{
G[u].push_back(v);
G[v].push_back(u);
}
}
}
}
scanf("%lld",&Q);
ll u,v;
ll cnt;
while(Q--)
{
scanf("%lld",&cmd);
if(!cmd)
{
scanf("%lld %lld",&u,&cnt);
val[u]+=cnt;
for(int i=0; i<G[u].size(); i++)
{
v=G[u][i];
sum[v]+=cnt;
}
}
else
{
scanf("%lld",&u);
if(vis[u])
printf("%lld\n",sum[u]);
else
{
sum[u]=0;
for(int i=0; i<G[u].size(); i++)
{
v=G[u][i];
sum[u]+=val[v];
}
printf("%lld\n",sum[u]);
}
}
}
}
return 0;
}