项目管理Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 3727 Accepted Submission(s): 1398 Problem Description 我们建造了一个大项目!这个项目有n个节点,用很多边连接起来,并且这个项目是连通的! Input 第一行一个整数T(1 <= T <= 3),表示测试数据的个数。 Output 对每个询问,输出一行表示答案。
Sample Input 1 3 2 1 2 1 3 6 0 1 15 0 3 4 1 1 1 3 0 2 33 1 2 Sample Output 4 15 15 |
下面说一个插入查询时间复杂度为sqrt(m)的算法:
对每个点定义两个值:val,sum,val记录自己的特征值,sum记录周边所有点特征值的和。
现在我们把所有的节点分成两类,重点(度数>=sqrt(m)),轻点(度数sqrt(m))。
插入:
轻点更新自己的val,同时更新所有的邻点的sum值
重点更新自己的val,同时只更新相邻重点的sum值(所以重点不需要连边到轻点)
查询:
轻点:暴力周边的所有邻点的val值。
重点:直接输出自己的sum值。
性质:
与重点相邻的重点不超过sqrt(m)个。
与轻点相邻的所有点不超过sqrt(m)个。
思路转自:http://www.cnblogs.com/fenice/p/5553105.html
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<sstream>
#include<cstring>
#include<bitset>
#include<cstdio>
#include<string>
#include<deque>
#include<stack>
#include<cmath>
#include<queue>
#include<set>
#include<map>
#define ls rt<<1
#define rs rt<<1|1
using namespace std;
typedef long long ll;
const int maxn = 1e5+100;
struct node
{
int u,v;
}q[maxn];
ll val[maxn],sum[maxn];
int n,m,cnt[maxn],block;
vector<int> g[maxn];
void init()
{
memset(cnt,0,sizeof(cnt));
memset(sum,0,sizeof(sum));
memset(val,0,sizeof(val));
for(int i=1;i<=n;i++)
g[i].clear();
}
int main()
{
int t;
int Q;
int k,x,y;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
init();
block = sqrt(1.0*m);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&q[i].u,&q[i].v);
cnt[q[i].u]++;
cnt[q[i].v]++;
}
for(int i=1;i<=m;i++)
{
int u = q[i].u;
int v = q[i].v;
if(cnt[u]>cnt[v])
swap(u,v);
if(cnt[u]<block)
{
g[u].push_back(v);
if(cnt[v]<block)
g[v].push_back(u);
}
else
{
g[u].push_back(v);
g[v].push_back(u);
}
}
scanf("%d",&Q);
for(int i=0;i<Q;i++)
{
scanf("%d",&k);
if(k==0)
{
scanf("%d%d",&x,&y);
val[x] += y;
for(int i=0;i<g[x].size();i++)
sum[g[x][i]] += y;
}
else
{
scanf("%d",&x);
if(cnt[x]<block)
{
ll ans = 0;
for(int i=0;i<g[x].size();i++)
ans += val[g[x][i]];
printf("%lld\n",ans);
}
else
printf("%lld\n",sum[x]);
}
}
}
return 0;
}
此题暴力也能过。。。