BZOJ4999 This Problem Is Too Simple!(树上差分+dfs序+树状数组)

  对每个权值分别考虑。则只有单点加路径求和的操作。树上差分转化为求到根的路径和,子树加即可。再差分后bit即可。注意树上差分中根的父亲是0,已经忘了是第几次因为这个挂了。

#include<iostream> 
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
#define N 100010
char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;}
int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
int read()
{
    int x=0,f=1;char c=getchar();
    while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
    while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
    return x*f;
}
int n,m,a[N],p[N],dfn[N],size[N],deep[N],fa[N][19],tree[N],ans[N*5],t,cnt;
struct data{int to,nxt;
}edge[N<<1];
struct data2
{
    int op,i,j,x,id;
    bool operator <(const data2&a) const
    {
        return x<a.x||x==a.x&&id<a.id;
    }
}q[N*5];
void addedge(int x,int y){t++;edge[t].to=y,edge[t].nxt=p[x],p[x]=t;}
void dfs(int k)
{
    dfn[k]=++cnt,size[k]=1;
    for (int i=p[k];i;i=edge[i].nxt)
    if (edge[i].to!=fa[k][0])
    {
        deep[edge[i].to]=deep[k]+1;
        fa[edge[i].to][0]=k;
        dfs(edge[i].to);
        size[k]+=size[edge[i].to];
    }
}
void add(int k,int x){while (k<=n) tree[k]+=x,k+=k&-k;}
int query(int k) {int s=0;while (k) s+=tree[k],k-=k&-k;return s;}
int lca(int x,int y)
{
    if (deep[x]<deep[y]) swap(x,y);
    for (int j=18;~j;j--) if (deep[fa[x][j]]>=deep[y]) x=fa[x][j];
    if (x==y) return x;
    for (int j=18;~j;j--) if (fa[x][j]!=fa[y][j]) x=fa[x][j],y=fa[y][j];
    return fa[x][0];
}
int main()
{
#ifndef ONLINE_JUDGE
    freopen("bzoj4999.in","r",stdin);
    freopen("bzoj4999.out","w",stdout);
    const char LL[]="%I64d\n";
#else
    const char LL[]="%lld\n";
#endif
    n=read(),m=read();
    for (int i=1;i<=n;i++) a[i]=read();
    for (int i=1;i<n;i++)
    {
        int x=read(),y=read();
        addedge(x,y),addedge(y,x);
    }
    fa[1][0]=1;dfs(1);
    for (int j=1;j<19;j++)
        for (int i=1;i<=n;i++)
        fa[i][j]=fa[fa[i][j-1]][j-1];
    int x=0;
    for (int i=1;i<=n;i++) x++,q[x].op=0,q[x].i=i,q[x].j=1,q[x].x=a[i],q[x].id=x;
    for (int i=1;i<=m;i++)
    {
        char c=getc();
        if (c=='C')
        {
            x++,q[x].op=0,q[x].i=read(),q[x].j=1,q[x].x=read(),q[x].id=x;
            x++,q[x].op=0,q[x].i=q[x-1].i,q[x].j=-1,q[x].x=a[q[x].i],q[x].id=x;
            a[q[x].i]=q[x-1].x;
        }
        else x++,q[x].op=1,q[x].i=read(),q[x].j=read(),q[x].x=read(),q[x].id=x;
    }
    m=x;
    sort(q+1,q+m+1);memset(ans,255,sizeof(ans));
    for (int i=1;i<=m;i++)
    {
        int t=i;
        while (t<m&&q[t+1].x==q[i].x) t++;
        for (int j=i;j<=t;j++)
        if (q[j].op)
        {
            int l=lca(q[j].i,q[j].j);
            ans[q[j].id]=query(dfn[q[j].i])+query(dfn[q[j].j])-query(dfn[l])-query(dfn[l==1?0:fa[l][0]]);
        }
        else add(dfn[q[j].i],q[j].j),add(dfn[q[j].i]+size[q[j].i],-q[j].j);
        for (int j=i;j<=t;j++)
        if (q[j].op==0) add(dfn[q[j].i],-q[j].j),add(dfn[q[j].i]+size[q[j].i],q[j].j);
        i=t;
    }
    for (int i=1;i<=m;i++) if (ans[i]>=0) printf("%d\n",ans[i]);
    return 0;
}

 

posted @ 2018-12-02 21:52  Gloid  阅读(177)  评论(0编辑  收藏  举报