bzoj3730震波(点分树,树状数组)

题目大意:n个节点的树,m次操作,每次修改每个点权值,或询问与节点x距离不超过k的所有点权值之和。

      对点分树的每个节点X用个线段树维或树状数组维护其子树中每个点到X的距离权值,再用另一个维护到fa[x]的距离权值(用于查询时容斥)。修改询问时沿着父节点往上跑 log n 层更新或查询。查询时需要减去前一层中的结果。。

    一开始用动态开节点的线段树+LCA玄学CE的了好几发(到现在也还不知道CE原因。。orz),换了个写法后不是T就是RE(心态逐步炸裂),然后不知羞耻的上网看了一下午别人的做法,将线段树换为树状数组后又RE了几发(心态完全炸裂),调到晚上最后终于过了。。菜枯了。

    代码:

    点分树+树状数组 。

#include
#include
#include
#include
using namespace std;
int A[100010],B[100010],vis[100010],ma[100010],siz[100010],root;
fa[100010][30],dep[100010],dis[100010][30],n;
vectorg[100010];
vectorT[2][100010];
void dfsroot(int u,int f,int sum){
     int i,v;
     siz[u]=1;
     ma[u]=0;
     for(i=0;i1) add(dis[u][i-1]+1,k-A[u],f,1);
    }
}
int fans(int u,int k){
    int i,v,f,f1,d,dd,ans=0;
    for(i=dep[u];i;i--){
        f=fa[u][i];
        f1=fa[u][i+1];
        d=dis[u][i];
        if(d<=k){
            dd=T[0][f].size()-1;
            dd=min(dd,k-d+1);
            ans+=qsum(dd,f,0);
            if(f1){
                dd=T[1][f1].size()-1;
                dd=min(dd,k-d+1);
                ans-=qsum(dd,f1,1);
            }
        }
    }
    return ans;
}
int main(){
    int a,b,c,ans=0,i,m;
    scanf("%d%d",&n,&m);
    for(i=1;i<=n;i++)  scanf("%d",&B[i]);
    for(i=1;i

 

     

 

你可能感兴趣的:(点分树)