有趣的树

有趣的树
(tree.pas/c/cpp)
【 问题描述】
伟大的花神发现树是很好玩的一个东西。 对于一棵带有点权的有根树, 她定义了 3 种操
作:
1.Changex。 表示把有根树的根变为 x。
2.Addxy。 表示在当前有根树中, 把 x 下方的子树中所有点权加上 y(包括 x 节点)。
3.Queryx。 表示询问当前有根树中, x 下方的子树中所有点权的和(包括 x 节点)。
注意当有根树的根发生变化时,“ x 下方的子树”也会随之变化。 一开始有根树的根为 1。
【 输入格式】
第一行 2 个整数 n,m, n 表示树上的点数,m 表示操作数。
接下来 n-1 行, 每行 2 个数 x、 y, 表示有一条连接 x-y 的边。
接下来一行 n 个数, 第 i 个数表示第 i 个点的点权。 点从 1 开始标号。
接下来 m 行, 每行为要进行的操作, 格式如上。
保证初始点权、 每次增加的点权的绝对值≤1000。
【 输出格式】
对于每个 Query 操作, 输出对应的答案。
【 样例输入】
5 10
1 2
2 3
1 4
4 5
491 285 564 419 997
Query 2
Add 5 568
Query 1
Add 2 -585
Query 2
Query 4
Change 1
Change 2
Change 2
Add 3 770
【 样例输出】
849
3324
-321
1984
【 数据规模】
对于 30%的数据: n≤20; m≤20;
对于 100%的数据: n≤1,000; m≤1,000;


这题看着很吓人,但其实十分简单,就是简单的暴力,不需要任何数据结构,也不需要什么特别的算法。
我们开一个vector,记录每条边(a[i]表示i点能到的,和能到i点的),
再开一个vector,记录有向边(就是父亲节点和子节点)(b[i]表示i是哪些点的父亲)。
Add:递归调用,调用node节点的儿子,全部加上要加的值

void ad(int node,int a){
    if(b[node].empty()){
        f[node]+=a;return;
    }
    else{
        f[node]+=a;
        for(int i=0;i<b[node].size();i++){
            ad(b[node][i],a);
        }
    }
}

Query:依然是递归调用,递归每一个儿子节点的值,并全部加起来

int query(int node){
    int ans=0;
    if(b[node].empty()){
        ans+=f[node];
        return ans;
    }
    else{
        ans+=f[node];
        for(int i=0;i<b[node].size();i++){
            int s1=b[node].size(),s2=b[node][i];
            ans+=query(b[node][i]);
        }
    }
    return ans;

Change:这里我们直接暴力,不用任和优化。直接将所有的b数组都清空,
然后广搜,以node为起点,搜索,搜过的点就为vis=1。一直搜下去,更
新b[i]的值,即可完成换根。

void change(int node){
    for(int i=1;i<=n;i++) b[i].clear();head=0;tail=1;q[tail]=node;vis[node]=1;
    while(head<tail){
        head++;
        for(int i=0;i<a[q[head]].size();i++){
            if(vis[a[q[head]][i]]!=1){
                b[q[head]].push_back(a[q[head]][i]);
                q[++tail]=a[q[head]][i];
                vis[a[q[head]][i]]=1;
            }
        }
    }
}

完整代码

#include<bits/stdc++.h>
#include<vector>
using namespace std;
int i,j,k,n,m,tot,ans,f[10005],pp,vis[10005],q[1000005],head,tail;
vector <int> a[10005];
vector <int> b[10005];
int read(){
    char c;while(c=getchar(),(c<'0'||c>'9')&&c!='-');
    int x=0,y=1;if(c=='-') y=-1;else x=c-'0';
    while(c=getchar(),c>='0'&&c<='9') x=x*10+c-'0';
    return x;
}
void ad(int node,int a){
    if(b[node].empty()){
        f[node]+=a;return;
    }
    else{
        f[node]+=a;
        for(int i=0;i<b[node].size();i++){
            int re=b[node][i];
            ad(b[node][i],a);
        }
    }
}
int query(int node){
    int ans=0;
    if(b[node].empty()){
        ans+=f[node];
        return ans;
    }
    else{
        ans+=f[node];
        for(int i=0;i<b[node].size();i++){
            int s1=b[node].size(),s2=b[node][i];
            ans+=query(b[node][i]);
        }
    }
    return ans;
}
void change(int node){
    for(int i=1;i<=n;i++) b[i].clear();head=0;tail=1;q[tail]=node;vis[node]=1;
    while(head<tail){
        head++;
        for(int i=0;i<a[q[head]].size();i++){
            if(vis[a[q[head]][i]]!=1){
                b[q[head]].push_back(a[q[head]][i]);
                q[++tail]=a[q[head]][i];
                vis[a[q[head]][i]]=1;
            }
        }
    }
}
int main()
{
    n=read();m=read();
    for(int i=1;i<=n-1;i++){
        int x=read(),y=read();
        a[x].push_back(y);a[y].push_back(x);
    }
    change(1);for(int i=1;i<=n;i++) vis[i]=0;
    for(int i=1;i<=n;i++) scanf("%d",&f[i]);
    for(int i=1;i<=m;i++){
        char c[5];cin>>c;char useu=getchar();
        if(c[0]=='A'){
            int x=read(),y;scanf("%d",&y);
            ad(x,y);
        }
        if(c[0]=='Q'){
            int x=read();
            int an=query(x);
            printf("%d\n",an);
        }
        if(c[0]=='C'){
            int x=read();
            change(x);
            for(int i=1;i<=n;i++) vis[i]=0;
        }
    }
    return 0;
}

2018.5.9更新:

好吧,我承认当时自己是一个蒟蒻。当时不知道树剖,这道题暴力做过去了就很开心,其实就是树剖的板子题,代码如下:高级数据结构还是强,比暴力快乐许多。虽然代码的行数……
#include<bits/stdc++.h>
#define MAXN 2005
using namespace std;
int read(){
    char c;int x=0,y=1;while(c=getchar(),(c<'0'||c>'9')&&c!='-');
    if(c=='-') y=-1;else x=c-'0';while(c=getchar(),c>='0'&&c<='9')
    x=x*10+c-'0';return x*y;
}
int n,m,dfn,cnt,root,val[MAXN],head[MAXN],nxt[MAXN],go[MAXN],gran[MAXN][12];
int son[MAXN],siz[MAXN],fa[MAXN],dep[MAXN],rank[MAXN],tid[MAXN],top[MAXN],sum[MAXN<<2],add[MAXN<<2];
string s;
void addedge(int x,int y){
    go[cnt]=y;nxt[cnt]=head[x];head[x]=cnt;cnt++;
    go[cnt]=x;nxt[cnt]=head[y];head[y]=cnt;cnt++;
}
void dfsI(int x,int father){
    fa[x]=father;dep[x]=dep[father]+1;
    son[x]=-1;siz[x]=1;gran[x][0]=fa[x];
    for(int i=1;(1<<i)<=dep[x];i++) gran[x][i]=gran[gran[x][i-1]][i-1];
    for(int i=head[x];i!=-1;i=nxt[i]){
        int to=go[i];
        if(to==fa[x]) continue;
        dfsI(to,x);siz[x]+=siz[to];
        if(son[x]==-1||siz[to]>siz[son[x]]) son[x]=to;
    }
}
void dfsII(int x,int t){
    top[x]=t;tid[x]=++dfn;rank[dfn]=val[x];
    if(son[x]==-1) return;
    dfsII(son[x],t);
    for(int i=head[x];i!=-1;i=nxt[i]){
        int to=go[i];
        if(to==fa[x]||to==son[x]) continue;
        dfsII(to,to);
    }
}
int lca(int u,int v){
    if(dep[u]>dep[v]) swap(u,v);
    for(int i=11;i>=0;i--)
     if(dep[u]<=dep[gran[v][i]]) v=gran[v][i];
    for(int i=11;i>=0;i--)
     if(gran[u][i]!=gran[v][i]) u=gran[u][i],v=gran[v][i];
    if(u!=v) u=gran[u][0],v=gran[v][0];
    return u;
}
void up(int node){sum[node]=sum[node<<1]+sum[node<<1|1];}
void down(int node,int ls,int rs){
    if(add[node]){
        add[node<<1]+=add[node];
        add[node<<1|1]+=add[node];
        sum[node<<1]+=add[node]*ls;
        sum[node<<1|1]+=add[node]*rs;
        add[node]=0;
    }
}
void build(int node,int l,int r){
    if(l==r){
        sum[node]=rank[l];return;
    }
    int mid=(l+r)>>1;
    build(node<<1,l,mid);
    build(node<<1|1,mid+1,r);
    up(node);
}
void update(int node,int l,int r,int L,int R,int ad){
    if(L<=l&&r<=R){
        sum[node]+=ad*(r-l+1);
        add[node]+=ad;return;
    }
    int mid=(l+r)>>1;
    down(node,mid-l+1,r-mid);
    if(L<=mid) update(node<<1,l,mid,L,R,ad);
    if(R>mid) update(node<<1|1,mid+1,r,L,R,ad);
    up(node);
}
int query(int node,int l,int r,int L,int R){
    if(L<=l&&r<=R){
        return sum[node];
    }
    int mid=(l+r)>>1,res=0;
    down(node,mid-l+1,r-mid);
    if(L<=mid) res+=query(node<<1,l,mid,L,R);
    if(R>mid) res+=query(node<<1|1,mid+1,r,L,R);
    return res;
}
void upLINK(int x,int ad){
    for(int i=head[x];i!=-1;i=nxt[i]){
        int to=go[i];
        if(to==fa[x]) continue;
        if(lca(to,root)==to){
            if(tid[to]-1>=1) update(1,1,n,1,tid[to]-1,ad);
            if(tid[to]+siz[to]<=dfn) update(1,1,n,tid[to]+siz[to],dfn,ad);
        }
    }
}
int quLINK(int x){
    int res=sum[1];
    for(int i=head[x];i!=-1;i=nxt[i]){
        int to=go[i];
        if(to==fa[x]) continue;
        if(lca(to,root)==to) res-=query(1,1,n,tid[to],tid[to]+siz[to]-1);
    }
    return res;
}
int main()
{
    memset(head,-1,sizeof(head));
    register int i;
    n=read();m=read();root=1;
    for(i=1;i<n;i++){
        int x=read(),y=read();
        addedge(x,y);
    }
    for(i=1;i<=n;i++) val[i]=read();
    dfsI(1,0);dfsII(1,1);build(1,1,n);
    for(i=1;i<=m;i++){
        cin>>s;
        if(s=="Change"){
            int x=read();root=x;
        }
        if(s=="Add"){
            int x=read(),y=read();
            if(x==root) update(1,1,n,1,dfn,y);
            else{
                if(lca(x,root)==x) upLINK(x,y);
                else update(1,1,n,tid[x],tid[x]+siz[x]-1,y);
            }
        }
        if(s=="Query"){
            int x=read();
            if(x==root) printf("%d\n",query(1,1,n,1,dfn));
            else{
                if(lca(x,root)==x)
                  printf("%d\n",quLINK(x));
                else printf("%d\n",query(1,1,n,tid[x],tid[x]+siz[x]-1));
            }
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值