zoukankan      html  css  js  c++  java
  • [ZJOI2008]树的统计

    题目描述

    一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w。

    我们将以下面的形式来要求你对这棵树完成一些操作:

    I. CHANGE u t : 把结点u的权值改为t

    II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值

    III. QSUM u v: 询问从点u到点v的路径上的节点的权值和

    注意:从点u到点v的路径上的节点包括u和v本身

    输入输出格式

    **输入格式:

    ** 输入文件的第一行为一个整数n,表示节点的个数。

    接下来n – 1行,每行2个整数a和b,表示节点a和节点b之间有一条边相连。

    接下来一行n个整数,第i个整数wi表示节点i的权值。

    接下来1行,为一个整数q,表示操作的总数。

    接下来q行,每行一个操作,以“CHANGE u t”或者“QMAX u v”或者“QSUM u v”的形式给出。

    输出格式:

    对于每个“QMAX”或者“QSUM”的操作,每行输出一个整数表示要求输出的结果。

    输入输出样例

    输入样例#1:

    4 1 2 2 3 4 1 4 2 1 3

    12 QMAX 3 4

    QMAX 3 3

    QMAX 3 2

    QMAX 2 3

    QSUM 3 4

    QSUM 2 1

    CHANGE 1 5

    QMAX 3 4

    CHANGE 3 6

    QMAX 3 4

    QMAX 2 4

    QSUM 3 4

    输出样例#1:

    4 1 2 2 10 6 5 6 5 16

    solution

    最喜欢一些难度虚高的题,比如说这一道。

    这道题就是最简单的树链剖分了,基本不需要什么其它的技巧了

    然而我的代码依旧在BZOJ上RE。

    题目要求查询最大值和区间和,活生生的套路,只要会基本的树链剖分这道题就可以A掉

    值得注意的是最大值初始赋为负数,因为权值可以为负(不然只有十分)

    代码

    #include<bits/stdc++.h>
    
    using namespace std;
    
    const int MAXN = 30000 + 10;
    
    const int inf = 1<<30;
    
    inline int read()
    {
        char ch;
        int fl=1;
        int xx=0;
        do{
          ch= getchar();
          if(ch=='-')
            fl=-1;
        }while(ch<'0'||ch>'9');
        do{
            xx=(xx<<3)+(xx<<1)+ch-'0';
            ch=getchar();
        }while(ch>='0'&&ch<='9');
        return xx*fl;
    }
    
    inline int Max(int a,int b)
    {
        if(a>=b) return a;
        else return b;
    }
    
    int n,q; 
    
    string op;
    
    int w[MAXN];
    
    struct node
    {
        int to;
        int next;
    };node g[MAXN*2];
    
    int cnt=0,head[MAXN];
    
    inline void addedge(int a,int b)
    {
        ++cnt;g[cnt].to=b;g[cnt].next=head[a];head[a]=cnt;return;
    }
    
    int fa[MAXN],dep[MAXN],son[MAXN],tot[MAXN];
    
    #define v g[i].to
    
    inline void dfs(int now)
    {
        son[now]=0,tot[now]=1;
        for(int i=head[now];i>0;i=g[i].next){
            if(v!=fa[now]){
                fa[v]=now;
                dep[v]=dep[now]+1;
                dfs(v);
                if(tot[son[now]]<tot[v]) son[now]=v;
                tot[now]+=tot[v];
            }
        }
    }
    
    int num[MAXN],top[MAXN],h=0;
    
    inline void dfs2(int now,int t)
    {
        top[now]=t;++h;num[now]=h;
        if(son[now]!=0) dfs2(son[now],t);
        for(int i=head[now];i>0;i=g[i].next)
        {
            if(v!=fa[now]&&v!=son[now])
                dfs2(v,v);
        }
    }
    
    struct s_tree
    {
        int l;
        int r;
        int sum;
        long long maxn;
        inline int mid()
        {
            return (l+r)>>1;
        }
    };s_tree tree[MAXN*4];
    
    #define lc o<<1
    #define rc o<<1|1
    
    inline void build(int o,int l,int r)
    {
        tree[o].l=l;
        tree[o].r=r;
        if(l==r)
        {
            tree[o].maxn=-inf;
            tree[o].sum=0;
        }
        else
        {
            int mid=tree[o].mid();
            build(lc,l,mid);
            build(rc,mid+1,r);
        }
    }
    
    inline void change(int o,int x,int y)
    {
        if(tree[o].l==tree[o].r){
            tree[o].maxn=tree[o].sum=y;
            return;
        }
        else
        {
            int mid=tree[o].mid();
            if(x<=mid) change(lc,x,y);
            else change(rc,x,y);
            tree[o].maxn=Max(tree[lc].maxn,tree[rc].maxn);
            tree[o].sum=tree[lc].sum+tree[rc].sum;
        }
    }
    
    inline long long findmax(int o,int x,int y)
    {
        int l=tree[o].l;
        int r=tree[o].r;
        if(x==l&&y==r) return tree[o].maxn;
        else
        {
            int mid=tree[o].mid();
            if(x>mid) return findmax(rc,x,y);
            else if(y<=mid) return findmax(lc,x,y);
            else return Max(findmax(lc,x,mid),findmax(rc,mid+1,y));
        }
    }
    
    inline long long findsum(int o,int x,int y)
    {
        int l=tree[o].l;
        int r=tree[o].r;
        if(x==l&&y==r) return tree[o].sum;
        else
        {
            int mid=tree[o].mid();
            if(x>mid) return findsum(rc,x,y);
            else if(y<=mid) return findsum(lc,x,y);
            else return (findsum(lc,x,mid)+findsum(rc,mid+1,y));
        }
    }
    
    inline long long qmax(int x,int y)
    {
        int tx=top[x],ty=top[y],ans=-inf;
        while(tx!=ty){
            if(dep[tx]>dep[ty]) 
            {
                swap(x,y);
                swap(tx,ty);
            }
            ans=Max(ans,findmax(1,num[ty],num[y]));
            y=fa[ty];ty=top[y];
        }
        if(x==y){
            return Max(ans,findmax(1,num[x],num[x]));
        }
        else{
            if(dep[x]>dep[y]) swap(x,y);
            return Max(ans,findmax(1,num[x],num[y]));
        }
    }
    
    inline long long qsum(int x,int y)
    {
        int tx=top[x],ty=top[y];
        long long ans=0;
        while(tx!=ty){
            if(dep[tx]>dep[ty]) 
            {
                swap(x,y);
                swap(tx,ty);
            }
            ans=ans+findsum(1,num[ty],num[y]);
            y=fa[ty];ty=top[y];
        }
        if(x==y){
            return ans+findsum(1,num[x],num[x]);
        }
        else{
            if(dep[x]>dep[y]) swap(x,y);
            return ans+findsum(1,num[x],num[y]);
        }
    }
    
    int main()
    {
        n=read();
        for(int i=1;i<=n;i++)
        {
            head[i]=-1;
        }
        for(int i=1;i<n;i++)
        {
            int x=read(),y=read();
            addedge(x,y);
            addedge(y,x);
        }
        fa[1]=0;dep[1]=1;
        dfs(1);
        dfs2(1,1);
        build(1,1,h);
        for(int i=1;i<=n;i++)
        {
            w[i]=read();
            change(1,num[i],w[i]);
        }
        q=read();
        for(int i=1;i<=q;i++)
        {
            cin>>op;
            int x=read(),y=read();
            if(op=="QMAX")
                printf("%lld
    ",qmax(x,y));
            else if(op=="QSUM")
                printf("%lld
    ",qsum(x,y));
            else
                change(1,num[x],y);
        }
    }
  • 相关阅读:
    Android 侧滑(双向滑动菜单)效果
    Android中PopupWindow中有输入框时无法弹出输入法的解决办法
    Android 调用图库选择图片实现和参数详解
    5.抽象类篇
    4.事件篇
    3.委托篇
    2.结构篇
    1.枚举篇
    读取excel到数据库里面
    Windows系统安装docker
  • 原文地址:https://www.cnblogs.com/wlzs1432/p/8869026.html
Copyright © 2011-2022 走看看