2014多校5(1008)HDU4918(点分治)

Query on the subtree

Time Limit: 16000/8000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 384    Accepted Submission(s): 133


Problem Description
bobo has a tree, whose vertices are conveniently labeled by 1,2,…,n. At the very begining, the i-th vertex is assigned with weight w i.

There are q operations. Each operations are of the following 2 types:

Change the weight of vertex v into x (denoted as "! v x"),
Ask the total weight of vertices whose distance are no more than d away from vertex v (denoted as "? v d").

Note that the distance between vertex u and v is the number of edges on the shortest path between them.
 

Input
The input consists of several tests. For each tests:

The first line contains n,q (1≤n,q≤10 5). The second line contains n integers w 1,w 2,…,w n (0≤w i≤10 4). Each of the following (n - 1) lines contain 2 integers a i,b i denoting an edge between vertices a i and b i (1≤a i,b i≤n). Each of the following q lines contain the operations (1≤v≤n,0≤x≤10 4,0≤d≤n).
 

Output
For each tests:

For each queries, a single number denotes the total weight.
 

Sample Input
   
   
4 3 1 1 1 1 1 2 2 3 3 4 ? 2 1 ! 1 0 ? 2 1 3 3 1 2 3 1 2 1 3 ? 1 0 ? 1 1 ? 1 2
 

Sample Output
   
   
3 2 1 6 6

题意:给了一棵带点权的树,支持两种操作! u w 将u的权值修改为w,? u d 询问与u的距离不超过d的点的权值和

思路:这道题拖了好久,AC以后还是很愉快的

            树分治

            对于每个分治中心center,用树状数组维护与它的距离为d的点权的和

            然后要查询与点u距离不超过d的点权值和,可以通过分治中心center来查询

            设u与center的距离为dis,则只需要统计与center距离为d-dis的点的权值和就好了,但是会将u所在的子树这部分算多余

            所以还要减去u所在子树的这部分权值和,所以还需要用树状数组维护每个子树中的点与对应的分治中心center距离为d的点的权值和,以及这个子树所对应的分治中心

            然后要查询的时候,只需要统计一遍u所在的所有子树以及对应的分治中心就可以了

#pragma comment(linker,"/STACK:102400000,102400000")
#include 
   
   
    
    
#include 
    
    
     
     
#include 
     
     
      
      
#include 
      
      
       
       
#include 
       
       
         #include 
        
          #include 
          #include 
          
            #include 
           
             #include 
            
              using namespace std; const int MAXN = 100010; int w[MAXN]; int head[MAXN]; int edge[MAXN<<1]; int next[MAXN<<1]; int esz; int vis[MAXN]; int center,mx,tot; int num[MAXN]; int cnum[MAXN]; int n; void addedge(int u,int v) { edge[esz]=v; next[esz]=head[u]; head[u]=esz++; } void getroot(int u,int p) { num[u]=1; cnum[u]=0; for(int i=head[u];i!=-1;i=next[i]){ int v=edge[i]; if(v==p||vis[v])continue; getroot(v,u); num[u]+=num[v]; cnum[u]=max(cnum[u],num[v]); } } void getcenter(int u,int p) { int tm=max(cnum[u],tot-num[u]); if(tm 
             
               sum; int sz; void init(int n,int w){ sz=n; sum.push_back(w); for(int i=1;i<=n;++i)sum.push_back(0); } void add(int x,int w){ if(x==0){ sum[0]+=w; return; } while(x<=sz){ sum[x]+=w; x+=(-x)&x; } } int query(int x){ if(x<0)return 0; if(x>sz)x=sz; int ans=sum[0]; while(x>0){ ans+=sum[x]; x-=(-x)&x; } return ans; } }T[MAXN<<1]; int CNT; int dis[MAXN]; struct node{ int root,subtree,d; node(int a=0,int b=0,int c=0):root(a),subtree(b),d(c){} }; vector 
              
                qt[MAXN]; void getdis(int u,int p) { dis[u]=0; for(int i=head[u];i!=-1;i=next[i]){ int v=edge[i]; if(v==p||vis[v])continue; getdis(v,u); dis[u]=max(dis[u],dis[v]+1); } } void getw(int u,int p,int dis) { T[vis[center]].add(dis,w[u]); T[CNT].add(dis,w[u]); qt[u].push_back(node(vis[center],CNT,dis)); for(int i=head[u];i!=-1;i=next[i]){ int v=edge[i]; if(v==p||vis[v])continue; getw(v,u,dis+1); } } void solve(int u) { getroot(u,0);mx=n;tot=num[u]; getcenter(u,0); vis[center]=++CNT; getdis(center,0); T[CNT].init(dis[center],w[center]); qt[center].push_back(node(vis[center],0,0)); for(int i=head[center];i!=-1;i=next[i]){ int v=edge[i]; if(vis[v])continue; ++CNT; T[CNT].init(dis[v]+1,0); getw(v,center,1); } for(int i=head[center];i!=-1;i=next[i]){ int v=edge[i]; if(vis[v])continue; solve(v); } } void init(int n) { memset(head,-1,sizeof(head));esz=0;CNT=0; for(int i=1;i<=n;i++)qt[i].clear(); for(int i=1;i<=(n<<1);i++)T[i].sum.clear(); memset(vis,0,sizeof(vis)); } int main() { int Q; while(scanf("%d%d",&n,&Q)!=EOF){ for(int i=1;i<=n;i++){ scanf("%d",&w[i]); } init(n); for(int i=1;i 
                
               
              
             
            
           
         
       
      
      
     
     
    
    
   
   
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值