zoukankan      html  css  js  c++  java
  • 【BZOJ】1036 [ZJOI2008]树的统计Count

    【算法】树链剖分+线段树

    【题解】模板题,见http://www.cnblogs.com/onioncyc/p/6207462.html

    调用线段数时要用新编号pos[i] !!!

    #include<cstdio>
    #include<cctype>
    #include<algorithm>
    using namespace std;
    const int maxn=30010,inf=0x3f3f3f3f;
    int pos[maxn],top[maxn],dfsnum,f[maxn],deep[maxn],size[maxn],first[maxn],n,tot,a[maxn];
    struct edge{int u,v,from;}e[maxn*3];
    struct tree{int l,r,sum,mx;}t[maxn*3]; 
    int read()
    {
        char c;int s=0,t=1;
        while(!isdigit(c=getchar()))if(c=='-')t=-1;
        do{s=s*10+c-'0';}while(isdigit(c=getchar()));
        return s*t;
    }
    void insert(int u,int v)
    {tot++;e[tot].u=u;e[tot].v=v;e[tot].from=first[u];first[u]=tot;}
    void dfs1(int x,int fa)
    {
        size[x]=1;
        for(int i=first[x];i;i=e[i].from)
         if(e[i].v!=fa)
          {
              int y=e[i].v;
              deep[y]=deep[x]+1;
              f[y]=x;
              dfs1(y,x);
              size[x]+=size[y];
          }
    }
    void dfs2(int x,int tp,int fa)
    {
        int k=0;
        pos[x]=++dfsnum;
        top[x]=tp;
        for(int i=first[x];i;i=e[i].from)
         if(e[i].v!=fa&&size[e[i].v]>size[k])k=e[i].v;
        if(k==0)return;
        dfs2(k,tp,x);
        for(int i=first[x];i;i=e[i].from)
         if(e[i].v!=fa&&e[i].v!=k)dfs2(e[i].v,e[i].v,x);
    }
    void build(int k,int l,int r)
    {
        t[k].l=l;t[k].r=r;
        if(l!=r)
         {
             int mid=(l+r)>>1;
             build(k<<1,l,mid);
             build(k<<1|1,mid+1,r);
         }
    }
    void change(int k,int x,int y)
    {
        int left=t[k].l,right=t[k].r;
        if(left==right){t[k].mx=y;t[k].sum=y;}
         else
          {
              int mid=(left+right)>>1;
              if(x<=mid)change(k<<1,x,y);
               else change(k<<1|1,x,y);
              t[k].sum=t[k<<1].sum+t[k<<1|1].sum;
              t[k].mx=max(t[k<<1].mx,t[k<<1|1].mx);
          }
    }
    int ask_mx(int k,int l,int r)
    {
        int left=t[k].l,right=t[k].r;
        if(l<=left&&right<=r)return t[k].mx;
         else
          {
              int mid=(left+right)>>1,maxs=-inf;
              if(l<=mid)maxs=ask_mx(k<<1,l,r);
              if(r>mid)maxs=max(maxs,ask_mx(k<<1|1,l,r));
              return maxs;
          }
    }
    int ask_sum(int k,int l,int r)
    {
        int left=t[k].l,right=t[k].r;
        if(l<=left&&right<=r)return t[k].sum;
         else
          {
              int mid=(left+right)>>1,sums=0;
              if(l<=mid)sums=ask_sum(k<<1,l,r);
              if(r>mid)sums+=ask_sum(k<<1|1,l,r);
              return sums;
          }
    }
    int solve_mx(int x,int y)
    {
        int maxs=-inf;
        while(top[x]!=top[y])
         {
             if(deep[top[x]]<deep[top[y]])swap(x,y);
             maxs=max(maxs,ask_mx(1,pos[top[x]],pos[x]));
             x=f[top[x]];
         }
        if(pos[x]>pos[y])swap(x,y);
        maxs=max(maxs,ask_mx(1,pos[x],pos[y]));
        return maxs;
    }
    int solve_sum(int x,int y)
    {
        int sums=0;
        while(top[x]!=top[y])
         {
             if(deep[top[x]]<deep[top[y]])swap(x,y);
             sums+=ask_sum(1,pos[top[x]],pos[x]);
             x=f[top[x]];
         }
        if(pos[x]>pos[y])swap(x,y);
        sums+=ask_sum(1,pos[x],pos[y]);
        return sums;
    }
    int main()
    {
        n=read();
        for(int i=1;i<n;i++)
         {
             int u=read(),v=read();
             insert(u,v);
             insert(v,u);
         }
        for(int i=1;i<=n;i++)a[i]=read();
        dfs1(1,-1);
        dfs2(1,1,-1);
        build(1,1,n);
        for(int i=1;i<=n;i++)change(1,pos[i],a[i]);
        int Q=read();char ch[10];
        for(int i=1;i<=Q;i++)
         {
             scanf("%s",ch);
             int u=read(),v=read();
             if(ch[1]=='H')change(1,pos[u],v);//QAQ 调用线段树必须用新编号,下面用旧编号是因为子程序中用了新编号T_T 
             if(ch[1]=='M')printf("%d
    ",solve_mx(u,v));
             if(ch[1]=='S')printf("%d
    ",solve_sum(u,v));
         }
        return 0;
    }
    View Code
  • 相关阅读:
    Python作业之分页显示内容
    Codeforces Round #368 (Div. 2)
    数论专项测试——约数个数和(lucas的数论)
    数论专题测试——逆元
    数论专题测试——幸运数字
    bzoj2219: 数论之神
    bzoj3283: 运算器
    梅森素数
    后缀数组
    Hash_1014: [JSOI2008]火星人prefix
  • 原文地址:https://www.cnblogs.com/onioncyc/p/6208902.html
Copyright © 2011-2022 走看看