• 树链剖分 BZOJ3589 动态树


    3589: 动态树

    Time Limit: 30 Sec  Memory Limit: 1024 MB
    Submit: 543  Solved: 193
    [Submit][Status][Discuss]

    Description

    别忘了这是一棵动态树, 每时每刻都是动态的. 小明要求你在这棵树上维护两种事件
    事件0:
    这棵树长出了一些果子, 即某个子树中的每个节点都会长出K个果子.
    事件1:
    小明希望你求出几条树枝上的果子数. 一条树枝其实就是一个从某个节点到根的路径的一段. 每次小明会选定一些树枝, 让你求出在这些树枝上的节点的果子数的和. 注意, 树枝之间可能会重合, 这时重合的部分的节点的果子只要算一次.
     

    Input

    第一行一个整数n(1<=n<=200,000), 即节点数.
    接下来n-1行, 每行两个数字u, v. 表示果子u和果子v之间有一条直接的边. 节点从1开始编号.
    在接下来一个整数nQ(1<=nQ<=200,000), 表示事件.
    最后nQ行, 每行开头要么是0, 要么是1.
    如果是0, 表示这个事件是事件0. 这行接下来的2个整数u, delta表示以u为根的子树中的每个节点长出了delta个果子.
    如果是1, 表示这个事件是事件1. 这行接下来一个整数K(1<=K<=5), 表示这次询问涉及K个树枝. 接下来K对整数u_k, v_k, 每个树枝从节点u_k到节点v_k. 由于果子数可能非常多, 请输出这个数模2^31的结果.

    Output

    对于每个事件1, 输出询问的果子数.

    Sample Input

    5
    1 2
    2 3
    2 4
    1 5
    3
    0 1 1
    0 2 3
    1 2 3 1 1 4

    Sample Output

    13

    HINT

     1 <= n <= 200,000, 1 <= nQ <= 200,000, K = 5.


    生成每个树枝的过程是这样的:先在树中随机找一个节点, 然后在这个节点到根的路径上随机选一个节点, 这两个节点就作为树枝的两端.

    Source

     
    树剖模板题,不过注意只能加一次,所以可以打标记,一次询问后记得清除标记
    另外,怎么对1<<31取模不懂
      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<algorithm>
      5 using namespace std;
      6 int n,m,cnt,tot;
      7 struct dt{
      8     int next,to;
      9 }edge[400010];
     10 struct data{
     11     int father,son,size,top,deep,getin,getout;
     12 }tree[200010];
     13 struct seg{
     14     int sum,tag1,tag2,ret;
     15 }segtree[800010];
     16 int head[200010];
     17 void add(int start,int end){
     18     edge[++cnt].next=head[start];
     19     edge[cnt].to=end;
     20     head[start]=cnt;
     21 }
     22 void dfs_weight(int u){
     23     tree[u].size=1;
     24     tree[u].son=0;
     25     for(int i=head[u];i;i=edge[i].next)
     26         if(edge[i].to!=tree[u].father){
     27             tree[edge[i].to].deep=tree[u].deep+1;
     28             tree[edge[i].to].father=u;
     29             dfs_weight(edge[i].to);
     30             tree[u].size+=tree[edge[i].to].size;
     31             if(tree[edge[i].to].size>tree[tree[u].son].size) tree[u].son=edge[i].to; 
     32         }
     33 }
     34 void dfs_build(int u,int tp){
     35     tree[u].getin=++tot;
     36     tree[u].top=tp;
     37     if(tree[u].son){
     38         dfs_build(tree[u].son,tp);
     39         for(int i=head[u];i;i=edge[i].next)
     40             if(edge[i].to!=tree[u].son&&edge[i].to!=tree[u].father) dfs_build(edge[i].to,edge[i].to); 
     41     }
     42     tree[u].getout=tot;
     43 }
     44 void up(int pos){
     45     segtree[pos].sum=segtree[pos<<1].sum+segtree[pos<<1|1].sum;
     46     segtree[pos].ret=segtree[pos<<1].ret+segtree[pos<<1|1].ret;
     47 }
     48 void update1(int pos,int d){
     49     segtree[pos].tag1=d;
     50     segtree[pos].ret=segtree[pos].sum*d;
     51 }
     52 void update2(int pos,int d,int ll,int rr){
     53     segtree[pos].tag2+=d;
     54     segtree[pos].sum+=(rr-ll+1)*d;
     55 }
     56 void down(int pos,int ll,int mid,int rr){
     57     if(segtree[pos].tag2){
     58         update2(pos<<1,segtree[pos].tag2,ll,mid);
     59         update2(pos<<1|1,segtree[pos].tag2,mid+1,rr);
     60         segtree[pos].tag2=0;
     61     }
     62     if(segtree[pos].tag1!=-1){
     63         update1(pos<<1,segtree[pos].tag1);
     64         update1(pos<<1|1,segtree[pos].tag1);
     65         segtree[pos].tag1=-1;
     66     }
     67 }
     68 void build(int pos,int ll,int rr){
     69     if(ll==rr){
     70         segtree[pos].tag1=-1;
     71         return;
     72     }
     73     int mid=(ll+rr)>>1;
     74     build(pos<<1,ll,mid);
     75     build(pos<<1|1,mid+1,rr);
     76 }
     77 void change(int pl,int pr,int d,int pos,int ll,int rr){
     78     if(pl>rr||pr<ll) return;
     79     if(segtree[pos].tag1==d) return;    
     80     if(pl<=ll&&pr>=rr){
     81         update1(pos,d);
     82         return;
     83     }
     84     int mid=(ll+rr)>>1;
     85     down(pos,ll,mid,rr);
     86     if(pr<=mid) change(pl,pr,d,pos<<1,ll,mid);
     87     else if(pl>mid) change(pl,pr,d,pos<<1|1,mid+1,rr);
     88     else{
     89         change(pl,mid,d,pos<<1,ll,mid);
     90         change(mid+1,pr,d,pos<<1|1,mid+1,rr);
     91     }
     92     up(pos);
     93 }
     94 void ask_some(int aa,int bb){
     95     int t1=tree[aa].top;
     96     int t2=tree[bb].top;
     97     while(t1!=t2){
     98         if(tree[t1].deep<tree[t2].deep){
     99             change(tree[t2].getin,tree[bb].getin,1,1,1,n);
    100             bb=tree[t2].father;
    101             t2=tree[bb].top;
    102         }
    103         else{
    104             change(tree[t1].getin,tree[aa].getin,1,1,1,n);
    105             aa=tree[t1].father;
    106             t1=tree[aa].top;
    107         }
    108     }
    109     if(tree[aa].deep<tree[bb].deep) change(tree[aa].getin,tree[bb].getin,1,1,1,n);
    110     else change(tree[bb].getin,tree[aa].getin,1,1,1,n);
    111 }
    112 void add_val(int pl,int pr,int d,int pos,int ll,int rr){
    113     if(pl>rr||pr<ll) return;
    114     if(pl<=ll&&pr>=rr){
    115         update2(pos,d,ll,rr);
    116         return;
    117     }
    118     int mid=(ll+rr)>>1;
    119     down(pos,ll,mid,rr);
    120     if(pr<=mid) add_val(pl,pr,d,pos<<1,ll,mid);
    121     else if(pl>mid) add_val(pl,pr,d,pos<<1|1,mid+1,rr);
    122     else{
    123         add_val(pl,mid,d,pos<<1,ll,mid);
    124         add_val(mid+1,pr,d,pos<<1|1,mid+1,rr);
    125     }
    126     up(pos);
    127 }
    128 int main(){
    129     scanf("%d",&n);
    130     int x=0,y=0;
    131     for(int i=1;i<n;i++){
    132         scanf("%d%d",&x,&y);
    133         add(x,y);
    134         add(y,x);
    135     }
    136     tree[1].deep=1;
    137     dfs_weight(1);
    138     dfs_build(1,1);
    139     build(1,1,n);
    140     scanf("%d",&m);
    141     int od=0,k=0;
    142     for(int i=1;i<=m;i++){
    143         scanf("%d",&od);
    144         if(od){
    145             scanf("%d",&k);
    146             for(int j=1;j<=k;j++){
    147                 scanf("%d%d",&x,&y);
    148                 ask_some(x,y);
    149             }
    150             printf("%d
    ",segtree[1].ret&((1<<31)-1));//???编译显示溢出 
    151             update1(1,0);
    152         }
    153         else{
    154             scanf("%d%d",&x,&y);
    155             add_val(tree[x].getin,tree[x].getout,y,1,1,n);
    156         } 
    157     }
    158     return 0;
    159 }
  • 相关阅读:
    Servlet----------在 Servlet 中的xml配置
    java连接数据库时的报错
    借用HTML5 插入视频。音频
    多线程的总结
    穷举法例子
    利用递归求最大公约数和最小公倍数
    递归逆序的使用
    Mac OS X运行程序出现bad interpreter: operation not permitted的解决方案
    C#之枚举类型
    窗体的单例模式
  • 原文地址:https://www.cnblogs.com/zwube/p/7077681.html
Copyright © 2020-2023  润新知