CodeForces

来源:互联网 发布:淘宝号信誉等级查询 编辑:程序博客网 时间:2024/06/06 05:09

题意:

有n个结点,标为1~n,,形成了一棵以1为根节点的树,有m个操作,,

操作有两种:

1。某个节点的值加上v,该节点的隔代都加上v,,该节点的子代以及子代的隔代都减去v。

2。查询某个节点的值。

n,m<=2e5

如果修改节点值直接暴力dfs的话,时间复杂度为O(n*m),显然超时。

可以看出,修改操作,其实是修改两个区间的值,,,那么可以想到线段树区间修改,lazy一下时间就可以优化到m*logn;

关键是如何保证修改区间时,区间是连续。如果直接以节点的标号为区间下标,显然是不行的。

这时可以为这棵树维护一个dfs序(具体见代码),保证修改某个位置时,修改的区间是连续的。

代码:

#include <bits/stdc++.h>using namespace std;const int maxn = 200000+7;struct node{    int x1,x2,y1,y2;}e[maxn];int n,m,a[maxn],bef[maxn],lazy[maxn*4],index = 1;vector<int> arr[maxn];void dfs1(int u,int dep,int fa){    if(dep==1)        bef[u] = index++;    int len = arr[u].size();    for(int i = 0;i<len;i++)    {        int v = arr[u][i];        if(v!=fa)        {            dfs1(v,1-dep,u);        }    }}void dfs2(int u,int fa){    int len = arr[u].size();    for(int i = 0;i<len;i++)        if(arr[u][i]!=fa)            dfs2(arr[u][i],u);    int r1 = bef[u],l2 = maxn,r2 = 0;    for(int i = 0;i<len;i++)    {        int v = arr[u][i];        if(v!=fa)        {            r1 = max(e[v].y2,r1);            l2 = min(e[v].x1,l2);            r2 = max(e[v].y1,r2);        }    }    e[u].x1 = bef[u],e[u].y1 = r1;    e[u].x2 = l2,e[u].y2 = r2;}void pushdown(int rt){    lazy[rt<<1] += lazy[rt];    lazy[(rt<<1)+1] += lazy[rt];    lazy[rt] = 0;}void build(int rt,int l,int r){    if(l==r)    {        lazy[rt] = 0;        return ;    }    int mid = (l+r)>>1;    build(rt<<1,l,mid);    build((rt<<1)+1,mid+1,r);    lazy[rt] = 0;}void update(int rt,int l,int r,int ql,int qr,int v){    if(ql<=l&&r<=qr)    {        lazy[rt] += v;        return ;    }    pushdown(rt);    int mid = (l+r)>>1;    if(ql<=mid)        update(rt<<1,l,mid,ql,qr,v);    if(qr>mid)        update((rt<<1)+1,mid+1,r,ql,qr,v);}int query(int rt,int l,int r,int q){    if(l==r)    {        return lazy[rt];    }    pushdown(rt);    int mid = (l+r)>>1;    if(q<=mid)        return query(rt<<1,l,mid,q);    return query((rt<<1)+1,mid+1,r,q);}int main(){    scanf("%d%d",&n,&m);    for(int i = 1;i<=n;i++)        scanf("%d",a+i);    for(int i = 1;i<=n-1;i++)    {        int u,v;        scanf("%d%d",&u,&v);        arr[u].push_back(v);        arr[v].push_back(u);    }    dfs1(1,1,0);    int len = arr[1].size();    for(int i = 0;i<len;i++)        dfs1(arr[1][i],1,1);    dfs2(1,0);    //for(int i = 1;i<=n;i++)      //  cout<<e[i].x2<<" "<<e[i].y2<<endl;    build(1,1,n);    while(m--)    {        int ty;        scanf("%d",&ty);        if(ty==1)        {            int q,v;            scanf("%d%d",&q,&v);            //cout<<e[q].x1<<" "<<e[q].y1<<endl;            //cout<<e[q].x2<<" "<<e[q].y2<<endl;            update(1,1,n,e[q].x1,e[q].y1,v);            if(e[q].y2!=0)            update(1,1,n,e[q].x2,e[q].y2,-v);        }        else        {            int q;            scanf("%d",&q);            printf("%d\n",query(1,1,n,bef[q])+a[q]);        }    }    return 0;}



区间修改+单点查询,用线段树写即耗内存,代码又长。

树状数组有一种操作可以高效的实现 区间修改+单点查询///。修改区间[L,R]相当于add(L,V);add(R+1,-V),,,但此时getSum(x)的值变为了下标为x的值。

代码:

#include <bits/stdc++.h>using namespace std;const int maxn = 200000+7;struct node{    int x1,x2,y1,y2;}e[maxn];int n,m,a[maxn],bef[maxn],tree[maxn],index = 1;vector<int> arr[maxn];void dfs1(int u,int dep,int fa){    if(dep==1)        bef[u] = index++;    int len = arr[u].size();    for(int i = 0;i<len;i++)    {        int v = arr[u][i];        if(v!=fa)        {            dfs1(v,1-dep,u);        }    }}void dfs2(int u,int fa){    int len = arr[u].size();    for(int i = 0;i<len;i++)        if(arr[u][i]!=fa)            dfs2(arr[u][i],u);    int r1 = bef[u],l2 = maxn,r2 = 0;    for(int i = 0;i<len;i++)    {        int v = arr[u][i];        if(v!=fa)        {            r1 = max(e[v].y2,r1);            l2 = min(e[v].x1,l2);            r2 = max(e[v].y1,r2);        }    }    e[u].x1 = bef[u],e[u].y1 = r1;    e[u].x2 = l2,e[u].y2 = r2;}int getSum(int x){    int ans = 0;    while(x>0)    {        ans += tree[x];        x -= x&(-x);    }    return ans;}void add(int k,int v){    while(k<=n)    {        tree[k] += v;        k += k&(-k);    }}int main(){    scanf("%d%d",&n,&m);    memset(tree,0,sizeof(tree));    for(int i = 1;i<=n;i++)        scanf("%d",a+i);    for(int i = 1;i<=n-1;i++)    {        int u,v;        scanf("%d%d",&u,&v);        arr[u].push_back(v);        arr[v].push_back(u);    }    dfs1(1,1,0);    int len = arr[1].size();    for(int i = 0;i<len;i++)        dfs1(arr[1][i],1,1);    dfs2(1,0);    //for(int i = 1;i<=n;i++)      //  cout<<e[i].x2<<" "<<e[i].y2<<endl;    while(m--)    {        int ty;        scanf("%d",&ty);        if(ty==1)        {            int q,v;            scanf("%d%d",&q,&v);            //cout<<e[q].x1<<" "<<e[q].y1<<endl;            //cout<<e[q].x2<<" "<<e[q].y2<<endl;            add(e[q].x1,v);            add(e[q].y1+1,-v);            if(e[q].y2!=0)                add(e[q].x2,-v),add(e[q].y2+1,v);        }        else        {            int q;            scanf("%d",&q);            printf("%d\n",getSum(bef[q])+a[q]);        }    }    return 0;}


原创粉丝点击