• Codevs 4633 [Mz]树链剖分练习


    4633 [Mz]树链剖分练习

    时间限制: 1 s    空间限制: 64000 KB    题目等级 : 大师 Master

    题目描述 Description

    给定一棵结点数为n的树,初始点权均为0,有依次q个操作,每次操作有三个参数a,b,c,当a=1时,表示给b号结点到c号结点路径上的所有点(包括b,c,下同)权值都增加1,当a=2时,表示询问b号结点到c号结点路径上的所有点权值之和。

    输入描述 Input Description

    第一行,一个正整数n。

    接下来n-1行,每行一对正整数x,y,表示x号结点和y号结点之间有一条边。

    第n+1行,一个正整数q。

    最后q行,每行一组正整数a,b,c,表示操作的三个参数。b和c可能相等。

    保证数据都是合法的。

    输出描述 Output Description

    若干行,每行一个非负整数表示答案。

    样例输入 Sample Input

    5

    1 2

    2 3

    1 4

    2 5

    5

    1 4 5

    2 1 5

    1 1 3

    2 5 3

    2 4 3

     

    样例输出 Sample Output

    3

    4

    6

     

    数据范围及提示 Data Size & Hint

    共有10个测试点,对于第i个测试点,当1<=i<=4时,n=q=10^i,当5<=i<=10时,n=q=10000*i。

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstring>
      4 using namespace std;
      5 #define maxn 10000*10
      6 struct Edge{ int to,next,value; }e[maxn*2+10];
      7 struct Node{ int l,r,sum,lazy; }tre[maxn*5];
      8 int dep[maxn],pos[maxn],size[maxn],son[maxn],fa[maxn];
      9 int top[maxn],head[maxn],tot=0,n,visx;
     10 void Add_Edge(int u,int v){
     11     e[++tot].to=v;e[tot].next=head[u];
     12     head[u]=tot;
     13 }
     14 void DFS_First(int now,int pre,int deepth){
     15     fa[now]=pre;size[now]=1;dep[now]=deepth;
     16     for(int i=head[now];i;i=e[i].next){
     17         int v=e[i].to;
     18         if(v!=pre&&!dep[v]){
     19             DFS_First(v,now,deepth+1);
     20             size[now]+=size[v];
     21             if(!son[now]||size[son[now]]<size[v])
     22                 son[now]=v;
     23         }
     24     }
     25 }
     26 void DFS_Second(int now,int Top){
     27     pos[now]=++visx;top[now]=Top;
     28     if(son[now])DFS_Second(son[now],Top);
     29     for(int i=head[now];i;i=e[i].next){
     30         int v=e[i].to;
     31         if(v!=son[now]&&v!=fa[now])DFS_Second(v,v);
     32     }
     33 }
     34 void Build(int now,int l,int r){
     35     tre[now].l=l;tre[now].r=r;
     36     if(l==r)return;
     37     int mid=(l+r)>>1;
     38     Build(now<<1,l,mid);Build(now<<1|1,mid+1,r);
     39 }
     40 void down(int now){
     41     int k=tre[now].lazy;
     42     tre[now<<1].lazy+=k;tre[now<<1|1].lazy+=k;
     43     tre[now].lazy=0;
     44     tre[now<<1].sum+=k*(tre[now<<1].r-tre[now<<1].l+1);
     45     tre[now<<1|1].sum+=k*(tre[now<<1|1].r-tre[now<<1|1].l+1);
     46 }
     47 int query(int now,int l,int r){
     48     if(l<=tre[now].l&&tre[now].r<=r)return tre[now].sum;
     49     if(tre[now].lazy)down(now);
     50     int ans=0,mid=(tre[now].l+tre[now].r)>>1;
     51     if(mid>=l)ans+=query(now<<1,l,r);
     52     if(mid<r)ans+=query(now<<1|1,l,r);
     53     tre[now].sum=tre[now<<1].sum+tre[now<<1|1].sum;
     54     return ans;
     55 }
     56 int QuerySum(int u,int v){
     57     int ans=0;
     58     while(top[u]!=top[v]){
     59         if(dep[top[u]] < dep[top[v]])swap(u,v);
     60         ans+=query(1,pos[top[u]],pos[u]);
     61         u=fa[top[u]];
     62     }
     63     if(dep[u]>dep[v])swap(u,v);
     64     ans+=query(1,pos[u],pos[v]);
     65     return ans;
     66 }
     67 void UpDate(int now,int l,int r){
     68     if(l<=tre[now].l&&tre[now].r<=r){
     69         tre[now].lazy++;
     70         tre[now].sum+=tre[now].r-tre[now].l+1;
     71         return ;
     72     }
     73     if(tre[now].lazy)down(now);
     74     int mid=(tre[now].l+tre[now].r)/2;
     75     if(mid>=l)UpDate(now<<1,l,r);
     76     if(mid<r)UpDate(now<<1|1,l,r);
     77     tre[now].sum=tre[now<<1].sum+tre[now<<1|1].sum;
     78     return ;
     79 }
     80 void Change(int u,int v){
     81     while(top[u]!=top[v]){
     82         if(dep[top[u]]<dep[top[v]])swap(u,v);
     83         UpDate(1,pos[top[u]],pos[u]);
     84         u=fa[top[u]];
     85     }
     86     if(dep[u]>dep[v])swap(u,v);
     87     UpDate(1,pos[u],pos[v]);
     88 }
     89 int main(){
     90     scanf("%d",&n);
     91     int q,x,y,z;
     92     for(int i=1,u,v;i<n;i++){
     93         scanf("%d%d",&u,&v);
     94         Add_Edge(u,v);Add_Edge(v,u);
     95     }
     96     DFS_First(1,0,0);
     97     DFS_Second(1,1);
     98     Build(1,1,n);
     99     
    100     scanf("%d",&q);
    101     while(q--){
    102         scanf("%d%d%d",&x,&y,&z);
    103         if(x==1)Change(y,z);
    104         else printf("%d
    ",QuerySum(y,z));
    105     }
    106     return 0;
    107 }
  • 相关阅读:
    数组指针和指针数组的区别
    C++虚函数
    C++容器
    红黑树
    COM RTS/CTS, DTR/DSR
    linux和windows多线程的异同
    socket
    C++vector使用
    select函数详解
    linux下头文件
  • 原文地址:https://www.cnblogs.com/suishiguang/p/6502759.html
Copyright © 2020-2023  润新知