用dfs序处理线段树的好题吗?

https://www.cnblogs.com/mountaink/p/9878918.html

分析:每次的选取必须选最优的一条链,那我们考虑一下选择这条链后,把这条路上的点的权值更新掉,再采取选最优的一条链的策略,如此往复。

    所以考虑利用dfs序来处理线段树,线段树维护的是最最优链的值,已经这条链的链跟,的dfs序。

   

#include<bits/stdc++.h>
using namespace std;
#define lson root<<1,l,midd
#define rson root<<1|1,midd+1,r
typedef long long ll;
const int M=2e5+5;
struct node{
    int v,nextt;
}e[M<<1];
ll a[M],tree[M<<2],mp[M<<2],dis[M<<2],lazy[M<<2];
int dfn[M],fa[M],cnt,tot,head[M],vis[M],L[M],R[M];
void addedge(int u,int v){
    e[cnt].v=v;
    e[cnt].nextt=head[u];
    head[u]=cnt++;
}

void up(int root){
    if(tree[root<<1]>tree[root<<1|1]){
        tree[root]=tree[root<<1];
        mp[root]=mp[root<<1];
    }
    else{
        tree[root]=tree[root<<1|1];
        mp[root]=mp[root<<1|1];
    }

}
void pushdown(int root){
    if(lazy[root]){
        ll c=lazy[root];
        tree[root<<1]-=c;
        tree[root<<1|1]-=c;
        lazy[root<<1]+=c;
        lazy[root<<1|1]+=c;
        lazy[root]=0;
    }
}
void build(int root,int l,int r){
    if(l==r){
        tree[root]=dis[l],mp[root]=l;
        return ;
    }
    int midd=(l+r)>>1;
    build(lson);
    build(rson);
    up(root);
}
void update(int LL,int RR,ll c,int root,int l,int r){
    if(LL<=l&&r<=RR){
        tree[root]-=c;
        lazy[root]+=c;
        return ;
    }
    pushdown(root);
    int midd=(l+r)>>1;
    if(LL<=midd)
        update(LL,RR,c,lson);
    if(RR>midd)
        update(LL,RR,c,rson);
    up(root);
}
void dfs(int u,int f){
    dfn[++tot]=u;
    L[u]=tot;
    dis[tot]=a[u]+dis[L[f]];
    for(int i=head[u];~i;i=e[i].nextt){
        int v=e[i].v;
        if(v==f)
            continue;
        dfs(v,u);
    }
    R[u]=tot;
}
int main(){
    int n,k;
    memset(head,-1,sizeof(head));
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++)
        scanf("%lld",&a[i]);
    for(int i=1;i<n;i++){
        int u,v;
        scanf("%d%d",&u,&v);
        addedge(u,v);
        addedge(v,u);
        fa[v]=u;
    }
    int root=1;
    while(fa[root])
        root=fa[root];
    //cout<<root<<"~!!"<<endl;
    dfs(root,0);
    build(1,1,n);
   /* for(int i=1;i<=4*n;i++)
        cout<<dis[i]<<endl;*/
    ll ans=0;
    int x;
    //cout<<"!!"<<endl;
    while(k--){
        ans+=tree[1];

        x=mp[1];
        while(x&&!vis[x]){
            update(L[dfn[x]],R[dfn[x]],a[dfn[x]],1,1,n);
            vis[x]=1;
            x=L[fa[dfn[x]]];
        }
    }
    printf("%lld
",ans);
    return 0;
}
View Code

 http://acm.hdu.edu.cn/showproblem.php?pid=3887

题意:给出一树,求在以每个节点为跟的树中,有几个是比他小的?

分析:用dfs给树进行编号,然后从小到大输出答案(query,是询问俩个dfs序区间)并更新线段树,更新时,是单点更新,+1就行了,因为如果在查询比之前点深度浅的的位置,就肯定会包含比他深度深且是他的子树的dfs序区间

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<vector>
using namespace std;
#define lson root<<1,l,midd
#define rson root<<1|1,midd+1,r
const int M=5e5+5;
int tree[M<<2],L[M],R[M],head[M],tot,cnt;
struct node{
    int v,nextt;
}e[M];
void addedge(int u,int v){
    e[cnt].v=v;
    e[cnt].nextt=head[u];
    head[u]=cnt++;
}
void up(int root){
    tree[root]=tree[root<<1]+tree[root<<1|1];
}
void dfs(int u,int f){
    L[u]=++tot;
    for(int i=head[u];~i;i=e[i].nextt){
        int v=e[i].v;
        if(v==f)
            continue;
        dfs(v,u);
    }
    R[u]=tot;
}
void build(int root,int l,int r){
    if(l==r){
        tree[root]=0;
        return;
    }
    int midd=(l+r)>>1;
    build(lson);
    build(rson);
}
void update(int pos,int c,int root,int l,int r){
    if(l==r){
        tree[root]+=c;
        return ;
    }
    int midd=(l+r)>>1;
    if(pos<=midd)
        update(pos,c,lson);
    else
        update(pos,c,rson);
    up(root);
}
int query(int L,int R,int root,int l,int r){
    if(L<=l&&r<=R){
        return tree[root];
    }
    int midd=(l+r)>>1;
    int ans=0;
    if(L<=midd)
        ans+=query(L,R,lson);
    if(R>midd)
        ans+=query(L,R,rson);
    return ans;
}
int main(){
    int n,root;
    while(~scanf("%d%d",&n,&root)){
        if(n==0&&root==0)
            break;
        tot=0,cnt=0;
        for(int i=0;i<=n;i++)
            head[i]=-1;
        memset(tree,0,sizeof(tree));
        for(int i=1;i<n;i++){
            int u,v;
            scanf("%d%d",&u,&v);
            addedge(u,v);
            addedge(v,u);
        }
        dfs(root,-1);
        build(1,1,n);
        for(int i=1;i<=n;i++){
            printf("%d",query(L[i],R[i],1,1,n));
            if(i==n)
                printf("
");
            else
                printf(" ");
            update(L[i],1,1,1,n);
        }

    }
    return 0;
}
View Code

 http://poj.org/problem?id=3321

题意:给出一颗苹果树,起初每个节点点权为1,然后询问是以询问节点为根问有多少个苹果,更新是单点更新,1->0,0->1

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#define lson root<<1,l,midd
#define rson root<<1|1,midd+1,r
using namespace std;
typedef long long ll;
const int M=1e5+5;
struct node{
    int v,nextt;
}e[M<<1];
int tree[M<<2],vis[M],L[M],R[M],cnt,tot,head[M];
void addedge(int u,int v){
    e[cnt].v=v;
    e[cnt].nextt=head[u];
    head[u]=cnt++;
}
void up(int root){
    tree[root]=tree[root<<1]+tree[root<<1|1];
}
void build(int root,int l,int r){
    if(l==r){
        tree[root]=1;
        return;
    }
    int midd=(l+r)>>1;
    build(lson);
    build(rson);
    up(root);
}
int query(int L,int R,int root,int l,int r){

    if(L<=l&&r<=R){
        return tree[root];

    }
    int midd=(l+r)>>1;
    int ans=0;
    if(L<=midd)
        ans+=query(L,R,lson);
    if(R>midd)
        ans+=query(L,R,rson);
    return ans;
}
void update(int pos,int c,int root,int l,int r){
    if(l==r){
        tree[root]+=c;
        return ;
    }
    int midd=(l+r)>>1;
    if(pos<=midd)
        update(pos,c,lson);
    else
        update(pos,c,rson);
    up(root);
}
void dfs(int u,int f){
    L[u]=++tot;
    for(int i=head[u];~i;i=e[i].nextt){
        int v=e[i].v;
        if(v==f)
            continue;
        dfs(v,u);
    }
    R[u]=tot;
}
char s[2];
int main(){
    int n;
    scanf("%d",&n);
    memset(head,-1,sizeof(head));
    for(int i=1;i<n;i++){
        int u,v;
        scanf("%d%d",&u,&v);
        addedge(u,v);
        addedge(v,u);
    }
    dfs(1,0);
    build(1,1,n);
    int m;
    scanf("%d",&m);
    while(m--){

        int x;
        scanf("%s%d",s,&x);
        if(s[0]=='Q'){
            printf("%d
",query(L[x],R[x],1,1,n));
        }
        else{
            if(vis[x]==0)
                update(L[x],-1,1,1,n),vis[x]=1;
            else
                update(L[x],1,1,1,n),vis[x]=0;
        }

    }
    return 0;
}
View Code

 http://codeforces.com/problemset/problem/620/E

分析:和数颜色的那道线段树题目差不多,只不过把树转化成dfs序而已。注意,在build时,要用dfn数组,而非L数组!!!!

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<vector>
#define lson root<<1,l,midd
#define rson root<<1|1,midd+1,r
using namespace std;
typedef long long ll;
const int M=4e5+5;
struct node{
    int v,nextt;
}e[M<<1];
ll tree[M<<2],lazy[M<<2];
int L[M],R[M],head[M],tot,cnt,a[M],dfn[M];
void up(int root){
    tree[root]=(tree[root<<1]|tree[root<<1|1]);
}
void pushdown(int root){
    if(lazy[root]){
        ll c=lazy[root];
        lazy[root<<1]=c,lazy[root<<1|1]=c;
        tree[root<<1]=c,tree[root<<1|1]=c;
        lazy[root]=0ll;
    }
}
void build(int root,int l,int r){
    if(l==r){
        tree[root]=(1ll<<(a[dfn[l]]-1))*1ll;
        return ;
    }
    int midd=(l+r)>>1;
    build(lson);
    build(rson);
    up(root);
}
void update(int L,int R,int c,int root,int l,int r){
    if(L<=l&&r<=R){
        tree[root]=(1ll<<(c-1))*1ll;
        lazy[root]=(1ll<<(c-1))*1ll;
        return ;
    }
    pushdown(root);
    int midd=(l+r)>>1;
    if(L<=midd)
        update(L,R,c,lson);
    if(R>midd)
        update(L,R,c,rson);
    up(root);
}
ll query(int LL,int RR,int root,int l,int r){
    if(LL<=l&&r<=RR){
        return tree[root];
    }
    ll ans=0;
    pushdown(root);
    int midd=(l+r)>>1;
    if(LL<=midd)
        ans|=query(LL,RR,lson);
    if(RR>midd)
        ans|=query(LL,RR,rson);
    up(root);
    return ans;
}
void dfs(int u,int f){
    L[u]=++tot;
    dfn[tot]=u;
    for(int i=head[u];~i;i=e[i].nextt){
        int v=e[i].v;
        if(v==f)
            continue;
        dfs(v,u);
    }
    R[u]=tot;
}
void addedge(int u,int v){
    e[cnt].v=v;
    e[cnt].nextt=head[u];
    head[u]=cnt++;
}
int sum(ll x){
    int t=0;
    while(x){
        if(x&1)
            t++;
        x>>=1;

    }
    return t;
}
int main(){
    int n,m;
    memset(head,-1,sizeof(head));
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
    }
    for(int i=1;i<n;i++){
        int u,v;
        scanf("%d%d",&u,&v);
        addedge(u,v);
        addedge(v,u);
    }
    dfs(1,0);
    build(1,1,n);
    while(m--){
        int op;
        scanf("%d",&op);
        if(op==1){
            int x,y;
            scanf("%d%d",&x,&y);
            update(L[x],R[x],y,1,1,n);
        }
        else{
            int x;
            scanf("%d",&x);
            printf("%d
",sum(query(L[x],R[x],1,1,n)));
        }
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/starve/p/11213877.html