zoukankan      html  css  js  c++  java
  • 【bzoj4765】 普通计算姬

    题意

      给出一棵有根树,$n$个点每个都有一个点权。$m$组操作每次可以修改一个点权或者询问编号在区间$[l,r]$的点的子树权值和的和。

    Solution

      我们对节点编号分块,每一块统计该块中的节点的子树权值和的和。dfs处理出修改一个节点,需要对应修改它的祖先和它的所在的哪些块。另外再开一个树状数组,树状数组中每一个元素是对应dfs的点的权值,这样我们可以求出任意子树的权值和。

      对于询问,在中间的块直接统计。两侧零散的块在树状数组上暴力查询子树权值和。所以令块的大小$S=sqrt{n/log{n}}$,复杂度$O(nsqrt{nlog{n}})$

    细节

      会爆long long

    代码

    // bzoj4765
    #include<algorithm>
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #define LL long long
    #define ULL unsigned long long
    #define inf (1ll<<30)
    #define Pi acos(-1.0)
    #define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout)
    using namespace std;
    
    const int maxn=100010;
    int head[maxn],L[maxn],R[maxn],t[maxn][350],pos[maxn],n,m,S,bn,cnt,dfn,Dargen;
    LL c[maxn],d[maxn],a[maxn];
    ULL s[maxn];
    struct edge {int to,next;}e[maxn<<1];
    
    int lowbit(int x) {
    	return x&-x;
    }
    void add(int x,LL val) {
    	for (int i=x;i<=n;i+=lowbit(i)) c[i]+=val;
    }
    LL query(int x) {
    	LL res=0;
    	for (int i=x;i;i-=lowbit(i)) res+=c[i];
    	return res;
    }
    void link(int u,int v) {
    	e[++cnt]=(edge){v,head[u]};head[u]=cnt;
    	e[++cnt]=(edge){u,head[v]};head[v]=cnt;
    }
    LL dfs(int x,int fa) {
    	L[x]=++dfn;d[pos[x]]++;
    	LL sum=a[x];add(L[x],a[x]);
    	for (int i=1;i<=bn;i++) t[x][i]=d[i];
    	for (int i=head[x];i;i=e[i].next) if (e[i].to!=fa) sum+=dfs(e[i].to,x);
    	R[x]=dfn;d[pos[x]]--;s[pos[x]]+=sum;
    	return sum;
    }
    int main() {
    	scanf("%d%d",&n,&m);
    	S=300;bn=n/S+(n%S!=0);
    	for (int i=1;i<=n;i++) pos[i]=(i-1)/S+1;
    	for (int i=1;i<=n;i++) scanf("%lld",&a[i]);
    	for (int u,v,i=1;i<=n;i++) {
    		scanf("%d%d",&u,&v);
    		if ((LL)u*v==0) Dargen=u+v;
    		else link(u,v);
    	}
    	dfs(Dargen,0);
    	for (int op,x,y,i=1;i<=m;i++) {
    		scanf("%d%d%d",&op,&x,&y);
    		if (op==1) {
    			LL d=y-a[x];a[x]=y;
    			for (int j=1;j<=bn;j++) s[j]+=d*t[x][j];
    			add(L[x],d);
    		}
    		if (op==2) {
    			ULL ans=0;
    			if (pos[x]==pos[y]) for (int j=x;j<=y;j++) ans+=query(R[j])-query(L[j]-1);
    			else {
    				for (int j=pos[x]+1;j<pos[y];j++) ans+=s[j];
    				for (int j=x;j<=S*pos[x];j++) ans+=query(R[j])-query(L[j]-1);
    				for (int j=(pos[y]-1)*S+1;j<=y;j++) ans+=query(R[j])-query(L[j]-1);
    			}
    			printf("%llu
    ",ans);
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    线程的基础知识
    并行编程与PLINQ
    swing组件中数据更新与UI更新的关系
    关于EDT和SwingUtilities的invokeLater和invokeAndWait
    内容页访问母版页页控件的方法
    asp.net 中一般应用处理程序使用session
    正则表达式学习日记
    C#中马赛克算法
    初学C与C在TC2.0上运行的注意事项
    delphi7中两个BT的Bug
  • 原文地址:https://www.cnblogs.com/MashiroSky/p/6515068.html
Copyright © 2011-2022 走看看