zoukankan      html  css  js  c++  java
  • BZOJ 4999 This Problem Is Too Simple!

    Description

    给您一颗树,每个节点有个初始值。
    现在支持以下两种操作:
    1. C i x(0<=x<2^31) 表示将i节点的值改为x。
    2. Q i j x(0<=x<2^31) 表示询问i节点到j节点的路径上有多少个值为x的节点。
     

    Input

    第一行有两个整数N,Q(1 ≤N≤ 100,000;1 ≤Q≤ 200,000),分别表示节点个数和操作个数。
    下面一行N个整数,表示初始时每个节点的初始值。
    接下来N-1行,每行两个整数x,y,表示x节点与y节点之间有边直接相连(描述一颗树)。
    接下来Q行,每行表示一个操作,操作的描述已经在题目描述中给出。
     

    Output

    对于每个Q输出单独一行表示所求的答案。
     

    Sample Input

    5 6
    10 20 30 40 50
    1 2
    1 3
    3 4
    3 5
    Q 2 3 40
    C 1 40
    Q 2 3 40
    Q 4 5 30
    C 3 10
    Q 4 5 30

    Sample Output

    0
    1
    1
    0

     

    题解:

      这个题目,树链剖分是十分显然的,但怎么查询权值为x的节点个数呢?

      可以为每个权值都开一棵线段树,当然要动态开点,因为开不下,所以离散化一下就可以了。

    代码:

    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <cmath>
    #include <iostream>
    #include <map>
    #define MAXN 100010
    using namespace std;
    struct edge{
        int first;
        int next;
        int to;
    }a[MAXN*2];
    struct tree{
        int ls,rs,sum;
    }tr[5000010];
    int dep[MAXN],son[MAXN],size[MAXN],fa[MAXN],top[MAXN],dfn[MAXN],w[MAXN];
    int numed=0,numtr=0,numcl=0,numdfn=0,n,q;
    int roof[MAXN*3],color[MAXN];
    map<int,int> mp;
    char s[3];
    
    void addedge(int from,int to){
        a[++numed].to=to;
        a[numed].next=a[from].first;
        a[from].first=numed;
    }
    
    void dfs1(int now,int f){
        fa[now]=f,dep[now]=dep[f]+1,size[now]=1;
        for(int i=a[now].first;i;i=a[i].next){
            int to=a[i].to;
            if(to==f) continue;
            dfs1(to,now);
            if(size[to]>size[son[now]]) son[now]=to;
            size[now]+=size[to];
        }
    }
    
    void dfs2(int now,int tp){
        top[now]=tp;dfn[now]=++numdfn;
        if(son[now]) dfs2(son[now],tp);
        for(int i=a[now].first;i;i=a[i].next){
            int to=a[i].to;
            if(to==fa[now]||to==son[now]) continue;
            dfs2(to,to);
        }
    }
    
    void change(int &x,int l,int r,int pos,int zhi){
        if(!x) x=++numtr;
        if(l==r&&l==pos){
            tr[x].sum+=zhi;
            return;
        }
        int mid=(l+r)/2;
        if(pos<=mid) change(tr[x].ls,l,mid,pos,zhi);
        else change(tr[x].rs,mid+1,r,pos,zhi);
        tr[x].sum=tr[tr[x].ls].sum+tr[tr[x].rs].sum;
    }
    
    int query(int x,int L,int R,int l,int r){
        if(!x) return 0;
        if(L==l&&R==r){
            return tr[x].sum;
        }
        int mid=(L+R)/2;
        if(r<=mid) return query(tr[x].ls,L,mid,l,r);
        else if(l>mid) return query(tr[x].rs,mid+1,R,l,r);
        else return query(tr[x].ls,L,mid,l,mid)+query(tr[x].rs,mid+1,R,mid+1,r);
    }
    
    int work(int x,int y,int rf){
        int topx=top[x],topy=top[y],ans=0;
        while(topx!=topy){
            if(dep[topx]<dep[topy]) swap(topx,topy),swap(x,y);
            ans+=query(rf,1,n,dfn[topx],dfn[x]);
            x=fa[topx];
            topx=top[x];
        }
        if(dep[x]<dep[y]) swap(x,y);
        ans+=query(rf,1,n,dfn[y],dfn[x]);
        return ans;
    }
    
    int main()
    {
        scanf("%d%d",&n,&q);
        for(int i=1;i<=n;i++){
            int x;scanf("%d",&x);
            if(!mp[x]) mp[x]=++numcl;
            color[i]=mp[x];
        }
        for(int i=1;i<=n-1;i++){
            int x,y;scanf("%d%d",&x,&y);
            addedge(x,y),addedge(y,x);
        }
        dfs1(1,0),dfs2(1,1);
        for(int i=1;i<=n;i++)
            change(roof[color[i]],1,n,dfn[i],1);
        while(q--){
            scanf("%s",s);
            if(s[0]=='C'){
                int x,y;scanf("%d%d",&x,&y);
                if(!mp[y]) mp[y]=++numcl;
                change(roof[color[x]],1,n,dfn[x],-1);
                color[x]=mp[y];
                change(roof[color[x]],1,n,dfn[x],1);
            }
            else{
                int x,y,z;scanf("%d%d%d",&x,&y,&z);
                if(!mp[z]) mp[z]=++numcl;
                printf("%d
    ",work(x,y,roof[mp[z]]));
            }
        }
        return 0;
    }
  • 相关阅读:
    oracle问题之死锁 (一)
    linux下oracle调试小知识
    Oracle实例名,服务名等概念区别与联系
    oracle 数据库、实例、服务名、SID
    Linux下启动/关闭Oracle
    Oracle监听器
    Oracle数据库、实例、用户、表空间、表之间的关系
    在Centos7上安装Oracle
    理财入门书籍
    [C/C++] VS 2015 C++ 插件
  • 原文地址:https://www.cnblogs.com/renjianshige/p/7616963.html
Copyright © 2011-2022 走看看