• BZOJ3589: 动态树


    题解:树剖sb题啊  想玩新花样啊 写虚树啊  写着写着又回到树剖了  咬牙重构树剖 写一万年发现树剖写挂了

    直接考虑 对于每次查询 等于选定某些区间统计价值 直接对于需要的区间打上标记 最后统计即可 查询结束后清除标记

    #include <bits/stdc++.h>
    const int MAXN=3e5+10;
    #define link(x) for(edge *j=h[x];j;j=j->next)
    using namespace std;
    struct edge{int t;edge*next;}e[MAXN<<1],*h[MAXN],*o=e;
    void add(int x,int y){o->t=y;o->next=h[x];h[x]=o++;}
    int dep[MAXN],son[MAXN],num[MAXN],fa[MAXN],n,m;
    int read(){
        int x=0,f=1;char ch=getchar();
        while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
        while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
        return f*x;
    }
    void dfs(int v,int pre,int deep){
        dep[v]=deep+1;fa[v]=pre;num[v]=1;
        link(v){
            if(j->t!=pre){
                dfs(j->t,v,deep+1);
                num[v]+=num[j->t];
                if(son[v]==-1||num[j->t]>num[son[v]])son[v]=j->t;
            }
        }
    }
    int p[MAXN],fp[MAXN],cnt,tp[MAXN];
    void dfs1(int v,int td){
        p[v]=++cnt;fp[p[v]]=v;tp[v]=td;
        if(son[v]!=-1)dfs1(son[v],td);
        link(v)if(son[v]!=j->t&&fa[v]!=j->t)dfs1(j->t,j->t);
    }
    int sum[MAXN<<2],flag[MAXN<<2],sum1[MAXN<<2];int flag1[MAXN<<2];
    inline void push(int rt,int l,int r){
        int mid=(l+r)>>1;
        sum[rt<<1]+=1LL*(mid-l+1)*flag[rt];
        sum[rt<<1|1]+=1LL*(r-mid)*flag[rt];
        flag[rt<<1]+=flag[rt];flag[rt<<1|1]+=flag[rt];
        flag[rt]=0;
        if(flag1[rt]==1){sum1[rt<<1]=sum[rt<<1];sum1[rt<<1|1]=sum[rt<<1|1];flag1[rt<<1]=flag1[rt<<1|1]=flag1[rt];}
        if(flag1[rt]==-1){sum1[rt<<1]=sum1[rt<<1|1]=0;flag1[rt<<1]=flag1[rt<<1|1]=-1;}
        flag1[rt]=0;
    }
    inline void up(int rt){sum[rt]=sum[rt<<1]+sum[rt<<1|1];sum1[rt]=sum1[rt<<1]+sum1[rt<<1|1];}
    inline void update(int rt,int l,int r,int ql,int qr,int vul){
        if(ql<=l&&r<=qr){sum[rt]+=1LL*(r-l+1)*vul;flag[rt]+=vul;return ;}
        int mid=(l+r)>>1;
        push(rt,l,r);
        if(ql<=mid)update(rt<<1,l,mid,ql,qr,vul);
        if(qr>mid)update(rt<<1|1,mid+1,r,ql,qr,vul);
        up(rt);
    }
    void update1(int rt,int l,int r,int ql,int qr,int vul){
        if(ql<=l&&r<=qr){
            if(vul==1)sum1[rt]=sum[rt],flag1[rt]=1;
            else sum1[rt]=0,flag1[rt]=-1;
            return ;
        }
        int mid=(l+r)>>1;
        push(rt,l,r);
        if(ql<=mid)update1(rt<<1,l,mid,ql,qr,vul);
        if(qr>mid)update1(rt<<1|1,mid+1,r,ql,qr,vul);
        up(rt);
    }
    inline void slove(int u,int v){
        int uu=tp[u];int vv=tp[v];
        while(uu!=vv){
            if(dep[uu]<dep[vv])swap(uu,vv),swap(u,v);
            update1(1,1,n,p[uu],p[u],1);
            u=fa[uu];uu=tp[u];
        }
        if(dep[u]>dep[v])swap(u,v);
        update1(1,1,n,p[u],p[v],1);
        return ;
    }
    int main(){
        scanf("%d",&n);int u,v,k,op;
        for(int i=1;i<=n;i++)son[i]=-1;
        for(int i=1;i<n;i++)scanf("%d%d",&u,&v),add(u,v),add(v,u);
        dfs(1,0,0);dfs1(1,1);
        scanf("%d",&m);
        for(int i=1;i<=m;i++){
            scanf("%d",&op);
            if(op==0)scanf("%d%d",&u,&k),update(1,1,n,p[u],p[u]+num[u]-1,k);
            else{
                scanf("%d",&k);
                while(k--)scanf("%d%d",&u,&v),slove(u,v);
                printf("%d
    ",sum1[1] & 0x7fffffff);
                update1(1,1,n,1,n,-1);
            }
        }
        return 0;
    }
    

    3589: 动态树

    Time Limit: 30 Sec  Memory Limit: 512 MB
    Submit: 756  Solved: 267
    [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.


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

  • 相关阅读:
    表格转换,多行聚集成列,长列转换成多行
    记第一次写数据库文章总结
    免疫 TCR BCR 病毒滴度
    Genome-wide Study Identifies Association between HLA-B*55:01 and Self-Reported Penicillin Allergy
    LD plot
    beta p-value SE
    蛋白截断变异(protein-truncating variant,PTV)
    The human noncoding genome defined by genetic diversity
    Fst计算
    LD Score regression文章 ;confounding
  • 原文地址:https://www.cnblogs.com/wang9897/p/9511829.html
Copyright © 2020-2023  润新知